ViewModel的出现主要为了解决两个问题:
1.当Actvitiy销毁重建过程中的数据恢复问题,虽然原来可以使用onSaveInstanceState()来完成,但是只支持能被序列化的数据而且是小量数据,对于大量数据则显得有点无力。
2.UI控制器的工作繁忙,UI控制器主要用于处理显示,交互,其他的额外操作可以委托给其他类完成,将不应该分配给UI的任务分离出来是必要的,这也就是上面所说的分离关注点原则。
下面是示意图
ViewModel实例
ViewModel在配置更改期间能自动保留其对象,以便它们所持有的数据可立即用于下一个 Activity 或片段 Fragment
具体的实例我在以前的一篇博客中讲过了,想要了解请点击 Android学习进度二 进行查看。
回到最上面的那个图,图说明了ViewModel
的作用域涉及到整个生命周期,当获取ViewModel时,ViewModel的生命周期限定为传入ViewModelProvider的对象的生命周期。也就是对于以下场景(引用官方示例)
1 public class SharedViewModel extends ViewModel { 2 private final MutableLiveData<Item> selected = new MutableLiveData<Item>(); 3 4 public void select(Item item) { 5 selected.setValue(item); 6 } 7 8 public LiveData<Item> getSelected() { 9 return selected; 10 } 11 } 12 13 public class MasterFragment extends Fragment { 14 private SharedViewModel model; 15 public void onCreate(Bundle savedInstanceState) { 16 super.onCreate(savedInstanceState); 17 model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class); 18 itemSelector.setOnClickListener(item -> { 19 model.select(item); 20 }); 21 } 22 } 23 24 public class DetailFragment extends Fragment { 25 public void onCreate(Bundle savedInstanceState) { 26 super.onCreate(savedInstanceState); 27 SharedViewModel model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class); 28 model.getSelected().observe(this, { item -> 29 // Update the UI. 30 }); 31 } 32 } 33
由于传入的是Activity,所以其作用域为整个Activity,不同的Fragment可以通过ViewModelProviders获取到同一个ViewModel,这样有以下的好处:
- Activity无须参与Fragment之间的交互。Activity与Fragment无关
- Fragment之间也无需互相建立联系,Fragment与Fragment无关
- 每个Fragment都有自己的生命周期,即使被替换也不会有任何影响
ViewModel加强,支持异常生命周期
有些时候在Activity被意外杀死,如清理后台等会直接跳过onDestory()而是回调onSaveInstanceState()异常杀死下的生命周期,这个时候ViewModel也会被杀死,再次恢复的时候便会被重建,这样,原来的数据也就丢失了,因此我们需要改进一下ViewModel以支持异常退出情况下的重建。
首先很容易是想到通过onSaveInstanceState() 来保存,然后通过SaveInstanceState 来恢复,虽然也是一种可行的方法,但是跟ViewModel没什么关联,ViewModel也提供了类似SavedInstanceState的方法。
SavedStateHandle :用于保存状态的数据类型,是一个key-value的map,类似于Bundle。
具体用法
1 public class ViewModelWithData extends ViewModel { 2 3 private MutableLiveData<Integer> number; 4 private SavedStateHandle handle; 5 6 private static final String KEY_NUMBER = "number"; 7 8 public ViewModelWithData(SavedStateHandle handle) { 9 this.handle = handle; 10 number = new MutableLiveData<>(); 11 number.setValue(0); 12 } 13 14 public MutableLiveData<Integer> getNumber() { 15 if (!handle.contains(KEY_NUMBER)) { 16 handle.set(KEY_NUMBER, 0); 17 } 18 return handle.getLiveData(KEY_NUMBER); 19 } 20 21 public void addNumber(int n) { 22 getNumber().setValue(getNumber().getValue() n); 23 } 24 }
1 public class LiveDataActivity extends AppCompatActivity { 2 3 private ViewModelWithData viewModelWithData; 4 5 ActivityLiveDataBinding binding; 6 7 @Override 8 protected void onCreate(Bundle savedInstanceState) { 9 super.onCreate(savedInstanceState); 10 binding = DataBindingUtil.setContentView(this, R.layout.activity_live_data); 11 viewModelWithData = ViewModelProviders.of(this, new SavedStateVMFactory(this)).get(ViewModelWithData.class); 12 binding.setData(viewModelWithData); 13 binding.setLifecycleOwner(this); 14 } 15 16 }