Android jetpack - ViewModel

it2023-06-30  68

简介

以生命周期的方式存储和管理界面相关的数据,从界面控制器逻辑中分离出视图数据所有权,让代码更易行且更高效

使用方式

自定义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 NonConfigurationInstances mViewModelStore = 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里面共享。
最新回复(0)