美文网首页android
Android Jetpack ViewModel解析

Android Jetpack ViewModel解析

作者: 唠嗑008 | 来源:发表于2019-12-31 17:43 被阅读0次

    前言

    最近几天把Jetpack中的3剑客Lifecycle+ViewModel+LiveData的使用和原理学习了一遍,这3者也是构建MVVM模式的核心。这个系列的工具,建议大家在官网学习:https://developer.android.google.cn/jetpack

    目前网上对这3者使用和源码解析的文章也沉淀了不少,大家可以自行查阅。本文换个方向来跟大家聊聊我所理解的关于ViewModel的一些内容。

    系列文章

    Android Jetpack ViewModel解析
    Android Jetpack LiveData解析
    Android Jetpack DataBinding原理浅析(简版)

    看看官方对Viewmodel作用的解释

    官方的Viewmodel用法例子

    官方的解释说明与案例还是很清晰的,所以就不做过多解释了。说一下我在学习过程中的一些疑问吧。

    1、在官网和Google的github demo中都建议在mvvm模式中的vm层去继承ViewModel,那为什么一定要继承ViewModel呢?我直接在VM中定义LiveData数据不行吗?是否继承ViewModel的区别在哪?

    下面通过一个例子来讲解,这里为了突出核心要点就用近乎伪代码的形式来表述。首先在mvvm的VM层去获取网络数据,实际上是model层执行的,然后当获取数据成功后调用LiveData对象的setValue()方法通知Activity的观察者去刷新UI。

    public class NewsViewModel extends ViewModel {
        private NewsModel newsModel;
        //adapter数据源
        private List<ItemNews> mList = new ArrayList<>();
        public MutableLiveData<List<ItemNews>> itemNewsLiveData = new MutableLiveData<>();
    
        public NewsViewModel() {
            newsModel = new NewsModel();
        }
    
        public void getNews() {
          mList =   newsModel.getNews();
          //通知活跃的观察者更新数据
          itemNewsLiveData.setValue(mList);
        }
    }
    

    Activity里面的观察者

     newsViewModel.itemNewsLiveData.observe(this, new Observer<List<ItemNews>>() {
                @Override
                public void onChanged(@Nullable List<ItemNews> itemNews) {
                 newsAdapter.updateAll(itemNews);
                }
            });
    

    这里按照官方的规范,只是在View层持有VM的引用,而VM不持有View的引用。到这一步我就有一个疑问,貌似不继承ViewModel也可以完成VM与View的交互,那引入它到底有什么好处呢?

    再回顾下官方的说法:

    ViewModel 类旨在以注重生命周期的方式存储和管理界面相关的数据。ViewModel类让数据可在发生屏幕旋转等配置更改后继续存在。

    上面说到ViewModel管理数据是和生命周期相关的,且能持久存储数据。那下面就简单解析一下是如何与生命周期相关的:

    官方ViewModel生命周期

    这里先说结论,源码验证待会儿再说。

    现在可以看出,好处1:
    因为ViewModel的生命周期是比Activity还要长,所以ViewModel可以持久保存UI数据,具体来说是Activity因为配置更改或者被系统意外回收的时候,会自动保存数据,然后在Activity重建的时候就可以继续使用销毁之前保存的数据。

    好处2:
    当使用ViewModel的 Activity 正常退出时,内部会调用ViewModel对象的 onCleared()方法,以便它可以清理资源。首先内部会释放ViewModel数据,同时你也可以在vm层重写这个方法去释放资源,取消网络等。

    好处3:
    在 Fragment 之间共享数据。这个比较简单,只要2个Fragment获取
    ViewModel对象时传入的LifecycleOwner一致就可以共享ViewModel中定义的数据。

    现在回头看刚才的例子,当配置改变导致Activity重建的时候,如果没有使用ViewModel存储数据,那么就会重新请求数据重绘页面;如果用ViewModel的话,就能用页面销毁之前保存的数据去直接显示视图。

    2、在MVVM中用了ViewModel+LiveData之后还有必要在Activity/Fragment的onDestory()方法中手动取消耗时任务(网络请求)吗?

    引入了ViewModelLiveData之后,可以实现vmview的解耦,只是view引用vm,而vm是不持有view的引用的。在activity退出之后即是还有网络在继续也不会引发内存泄漏和空指针异常,所以不在ondestory取消网络也是可以的。如果你还是想取消,可以重写onCleared()方法去做。

    原理解析

    ViewModel源码真的很简单,就几个类,实际上实际上真正的业务处理核心就只有ViewModelProvider,其他都是辅助。

    • ViewModel类是一个抽象方法,只有一个空方法onCleared(),它会在onDestory的时候被调用,所以你可以重写这个方法,在里面做些释放资源、取消网络的操作。
    • AndroidViewModel是继承ViewModel的,就多了一步,提供Application参数
    • ViewModelStore:和名字一样,就是存储ViewModel的,它里面定义了一个HashMap来存储ViewModel,key值是ViewModel全路径+一个默认的前缀。大概这样:key=android.arch.lifecycle.ViewModelProvider.DefaultKey:com.zx.mvvmdemo.vm.NewsViewModel
    • ViewModelStoreOwner:是一个接口,只有一个方法,是获取ViewModelStore对象的
      ViewModel核心类

    通常定义ViewModel之后,通过如下方式获取ViewModel对象

    newsViewModel = ViewModelProviders.of(this).get(NewsViewModel.class);
    

    of传FragmentActivity或者Fragment对象。
    这里主要分析2个问题:

    • 1、ViewModel是如何创建的?
    • 2、ViewModel是如何保存数据的?

    这里不按照执行流程去阅读源码那样分析,因为这么详细的内容已经有人写了,我就讲一下关键的思路,细节的话,推荐一遍不错的:
    Android ViewModel,再学不会你砍我

    从入口来看,是外观模式,ViewModelProviders就是外观类,真正的业务处理是在ViewModelProvider注意前者多了一个s,核心就在ViewModelProviderget()方法

    ViewModelProvider.get

    逻辑大致如下:

    首先从ViewModelStore的HashMap这个缓存中取取数据,如果有直接返回ViewModel,如果没有通过ViewModelProvider内部的工厂类去创建,ViewModel的创建具体来说是通过反射区做的,并且保存在缓存中,这样就获取到了ViewModel对象。

    到这里,问题1就解决了。下面看看问题2,数据是如何保存的。
    数据保存是在FragmentActivity中实现的。

    因为配置变化导致Activity销毁重建以前的方案是保存数据在onSaveInstanceState,而还原在onRestoreInstanceState,但是这2个方法是有很大瑕疵的,于是在新的SDK中FragmentActivity内置了2个新的方法onRetainNonConfigurationInstancegetLastNonConfigurationInstance,更多细节可以参考:
    https://www.cnblogs.com/dengxianzhi/articles/2248655.html

    其中onRetainNonConfigurationInstance是在onStop() 和 onDestroy()之间被调用,它内部会保存ViewModel数据;而在onCreate的时候会调用getLastNonConfigurationInstance来恢复数据。

    借用刚才文章的一张图来说明保存恢复数据流程 保存恢复数据流程

    总结

    1、让mvvm的vm去继承ViewModel,并在其内部定义、管理UI所需的数据,不仅可以让View和ViewModel解耦,同时其内部自动关联生命周期,可以减少在Activity的生命周期方法中写大量的样板代码。

    2、ViewModel保存数据这个功能还是有点用的。一开始我觉得当屏幕旋转的时候你可以通过configChanges的设置来阻止它的重建,这样就不需要viewmodel保存数据了。但是其它的一些意外情况也是有可能导致Activity重建的,比如当前activity在填写一堆表单数据,中间打开了其他app,在后台被回收了,后面再进入的时候如果没有保存就得重填,如果你的UI数据放在ViewModel的话就会自动回复,这样看来,ViewModel的保存数据功能是不是还挺有用呢

    3、利用ViewModel共享数据可以更简洁,减少很多不必要的接口。

    4、友情提示:在创建ViewModel对象的时候不能手动去new一个,而是通过Provider的方式去获取,这样的话才能利用ViewModel的那些优势。

    相关文章

      网友评论

        本文标题:Android Jetpack ViewModel解析

        本文链接:https://www.haomeiwen.com/subject/ietvoctx.html