美文网首页
ViewModel的原理

ViewModel的原理

作者: 转身搁浅昨天 | 来源:发表于2020-05-24 22:38 被阅读0次

    众所周知,ViewModel的作用在于以可感知生命周期的方式存储与管理UI相关的数据,它允许数据在例如屏幕旋转这样的配置发生变化时得以保存,那系统又是如何做到保存ViewModel的呢,让我们从源码中去溯本追源吧。

    AndroidX支持库中的AppCompatActivity继承自FragmentActivity,而后者又继承自ComponentActivity,ComponentAcitivty实现了ViewModelStoreOwner接口,该接口定义如下: 屏幕快照 2020-05-22 下午8.52.32.png

    很显然,实现该接口的类需要能够提供一个ViewModelStore,而ViewModelStore即为用于存储ViewModel对象的仓库,其内部通过一个HashMap管理ViewModel。

    当需要获取ViewModel时,需先创建ViewModelProvider实例,在2.2.0版本的ViewModel库中,不再通过ViewModelProvider的静态of方法获取实例,而需要通过ViewModelProvider的构造函数去创建实例,其存在如下构造函数: 屏幕快照 2020-05-24 下午10.27.15.png 在这个构造函数内,会通过ViewModelStoreOwner的getViewModelStore方法获取到ViewModelStore,而ViewModelProvider的get方法则使用该ViewModelStore去获取ViewModel,其获取逻辑如下: 屏幕快照 2020-05-24 下午9.08.55.png 从代码中可看出,如果ViewModel已经在ViewModelStore中存在,则直接从中获取,否则会创建ViewModel并存入ViewModelStore中。因为AppCompatActivity实现了ViewModelStoreOwner接口,所以我们可以传入AppCompatActivity对象获取到ViewModelProvider实例,进而获取ViewModel对象。 接下来看下ComponentActivity对ViewModelStoreOwner接口的实现: 屏幕快照 2020-05-22 下午8.57.54.png 在方法内部会先判断当前是否已经存在ViewModelStore,如果不存在则先获取NonConfiguratioInstances并从其中取出ViewModelStore,否则创建一个ViewModelStore。获取NonConfigurationInstances实例的代码如下: 屏幕快照 2020-05-24 下午10.20.41.png 所以这里的NonConfigurationInstances就是系统保存ViewModel的关键所在。
    那么这个NonConfigurationInstances又是从何而来的呢,通过方法跟踪,可找到其在Activity的attach方法中通过方法参数传入
    @UnsupportedAppUsage
    final void attach(Context context, ActivityThread aThread,
                Instrumentation instr, IBinder token, int ident,
                Application application, Intent intent, ActivityInfo info,
                CharSequence title, Activity parent, String id,
                NonConfigurationInstances lastNonConfigurationInstances,
                Configuration config, String referrer, IVoiceInteractor voiceInteractor,
                Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken) {
                  ……
              mLastNonConfigurationInstances = lastNonConfigurationInstances;
                  ……
    }
    

    Activity的attach方法是在Activity的加载流程中由ActivityThread的performLaunchActivity调用的,调用时传入的是ActivityRecordClient中的NonConfigurationInstances对象,那ActivityRecordClient又是在什么时候保存的NonConfigurationInstances对象的呢,这就要从Activity因为配置变化被销毁时查起了。

    当Activity因为配置变化被销毁时,在其销毁流程中ActivityThread会调用performDestroyActivity方法,该方法内部会回调Activity的retainNonConfigurationInstances方法获取NonConfigurationInstances并保存在ActivityRecordClient中以备之后Activity重建之需,以下是retainNonConfigurationInstances方法的部分流程:

    NonConfigurationInstances retainNonConfigurationInstances() {
            Object activity = onRetainNonConfigurationInstance();
            ……
            NonConfigurationInstances nci = new NonConfigurationInstances();
            nci.activity = activity;
            ……
            return nci;
    }
    
    其中onRetainNonConfigurationInstance()方法由ComponentActivity进行了覆写: 屏幕快照 2020-05-24 下午10.04.02.png

    onRetainNonConfigurationInstances方法的主要逻辑就是创建了一个NonConfigurationInstances对象(此NonConfigurationInstances类与前头的NonConfigurationInstances类不是同一个类),并将当前Activity的ViewModelStore保存到了所创建的对象的viewModelStore变量中,从而使得Activity在销毁后重建时能获取到销毁前的ViewModelStore,进而可获取到销毁前的ViewModel。onRetainNoConfigurationInstance方法返回的NonConfigurationInstance对象最终被存储到了retainNonConfigurationInstances方法中创建的NonConfigurationInstances对象的activity变量里。

    需要注意的是,如果Activity是正常的销毁,那么ViewModelStore会清空其保存的所有ViewModel,而如果是因为配置变化而被销毁,则不清空,这个逻辑可由ComponentActivity的构造函数中觅得: 屏幕快照 2020-05-22 下午10.05.53.png

    相关文章

      网友评论

          本文标题:ViewModel的原理

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