简介
以生命周期的方式存储和管理界面相关的数据,从界面控制器逻辑中分离出视图数据所有权,让代码更易行且更高效
使用方式
- 自定义ViewModel (ViewModel不需要额外引入其他配置),直接继承ViewModel,如果自定义的viewmodel需要使用context,可继承自AndroidViewModel,这里面会维护ApplicationContext,不要将Activity中context或者其他context传入ViewModel,因为ViewModel的生命周期比Activity或者Fragment长,如果引用它们的Context会造成内存泄漏
class VodViewModel : ViewModel() {
//一般配合LiveData使用private val movies: MutableLiveData<List<Movie>> by lazy {
MutableLiveData().also {
loadMovies()}}fun getMovies(): LiveData<List<Movie>> {
return movies}private fun loadMovies() {
// 执行数据加载,一般是网络请求}
}class LiveViewModel : ViewModel() {
private val movies: MutableLiveData<List<Movie>> by lazy {
MutableLiveData().also {
loadMovies()}}fun getMovies(): LiveData<List<Movie>> {
return movies}private fun loadMovies() {
// 执行数据加载,一般是网络请求}
}
- 在Activity或fragment中使用,一般在onCreate方法中调用,一旦调用viewModel就会被实例化,直至Activity或fragment被销毁后自动调用onCleared()解除
ViewModelProvider viewModelProvider = new ViewModelProvider(this, new ViewModelProvider.NewInstanceFactory());
VodViewModel vodViewModel = viewModelProvider.get(VodViewModel.class);
//配合LiveData使用即可在数据发生变化时自动更新界面
vodViewModel.getMovies().observe(this, movies -> {
// update UI
});
LiveViewModel liveViewModel = viewModelProvider.get(LiveViewModel.class);
liveViewModel.getMovies().observe(this, movies -> {
// update UI
});
注:
-
ViewModelProvider(ViewModelStoreOwner owner, Factory factory),使用这个构造参数创建了ViewModelProvider,再通过ViewModelProvider的get方法获取想要的viewModel,所以传入的this(即Activity或者Application)需要继承自ViewModelStoreOwner,如果你的Activity继承自AppCompatActivity或者FragmentActivity就不需要管,因为它们默认已经实现了ViewModelStoreOwner接口
-
传入的第一个参数ViewModelStoreOwner即将当前界面控制器与ViewModelProvider进行了绑定,ViewModelProvider内部有一个属性ViewModelStore就是通过ViewModelStoreOwner.getViewModelStore()获取的,ViewModelStore里维护一个HashMap,即存储当前界面控制器需要观察的所有ViewModel,在界面控制器销毁时调用ViewModelStore的clear方法,在这里对map里面所有的ViewModel执行onCleared,然后清空map
-
当配置发生变化时虽然Activity调用了onDestroy方法但是ViewModel还是之前的ViewModel,而真正销毁时调用的onDestroy就会调用ViewModel的OnCleared结束ViewModel的一生。这个原因在FragmentActivity中找到了答案,之前说过ViewModelProvider的属性ViewModelStore是通过传入的ViewModelStoreOwner中getViewModelStore()方法获取的,FragmentActivity源码中getViewModelStore()可以看到
NonConfigurationInstances nc =(NonConfigurationInstances) getLastNonConfigurationInstance();
if (nc != null) {
// Restore the ViewModelStore from NonConfigurationInstancesmViewModelStore = nc.viewModelStore;
}
了然,当配置发生变化时会自动保存viewModelStore,在恢复后如果发现是配置变化就使用之前的viewModelStore,viewModelStore没变,其内保存各个VIewModel的Map也就不会变
- 由于每个Activity传入的ViewModelStoreOwner不同,所以即使它们有相同的ViewModel其内数据也不同
- Fragment传入的getActivity代表了,一个Activity上所有的Fragment都是共用一个ViewModelStore,也就表明两个fragment之间可以通过使用相同的ViewModel来共享数据
- 之前一直疑惑为什么要用Map来存,讲道理一个Activity使用一个ViewModel就好,如果有多个数据,比如UserLiveData和SettingsLiveData只要把它们都放在同一个ViewModel就好。个人见解:原因1解耦,不想把不同数据的操作放在一起;原因2性能,这样设计的原因是为了Fragment使用,一个Activity上可能有多个Fragment,而每个Fragment里面有不同的数据可能性很小,所以间接可以理解为每个Fragment对应一个ViewModel各自管理各自的数据,而所有这些ViewModel都放在一个Map里面共享。