Android ViewModel源码分析
本文将分成以下几个部分:
ViewModel如何被构建出来?
ViewModel为什么能存储数据?

PART 1 ViewModel的构建流程
我们通常可以使用by viewModels()的方式构建ViewModel的实例,viewModels()作为ComponentActivity的扩展函数,会返回一个ViewModelLazy。
ViewModelStore和ViewModelFactory
这里需要注意一下,传入的viewModelStore和defaultViewModelProviderFactory都是ComponentActivity的属性。
ViewModelStore基于HashMap的结构进行ViewModel的存储:
当ComponentActivity被销毁时清除其中的数据:
Factory默认使用的是SavedStateViewModelFactory,具体的构建过程下面会说到。
说回刚才的ViewModelLazy,Lazy作为一个懒加载的通用接口,其中的value属性表示在Lazy对象的生命周期过程中只能被修改一次的属性。所以具体看看ViewModelLazy对于value的get方法的重写:
首先是调用ViewModelProvider的构造函数,然后调用get方法:
在后面的get方法中可以看到,如果ViewModelStore中的map存在缓存,我们直接从缓存中找到ViewModel,否则调用KeyedFactory#create,SavedStateViewModelFactory就是一个KeyedFactory的子类。
create方法中通过构建SavedStateHandleController,然后向ViewModel中塞入了一个SavedStateHandle,从而构建了ViewModel。SavedStateHandle就是ViewModel能够进行状态保存的关键所在,这里先卖个关子,最后一节会详细解释。
至此,我们已经稍微涉及到了ViewModel状态保存的关键角色,这些关键角色在后面的调用链中我使用不同颜色的方块表示:

以上的ViewModel的构建部分已经介绍完毕,总结如下图:

ViewModel创建过程总结:
ViewModel创建过程在Kotlin中基于by 语法,但是本质上还是通过ViewModelProvider创建,所以我们在Java中调用的是ViewModelProvider的方法。
ViewModelProvider创建ViewModel的奥秘在于ComponentActivity中的两个关键角色,ViewModelStore和SavedStateViewModelFactory。如果存在ViewModel的缓存,ViewModelStore会取出,如果没有缓存,通过Factory构建。
Factory构建时放入了SavedStateHandle,它是ViewModel可以进行状态保存的奥秘所在。
下面进入PART2,详细讲述SavedState这些兄弟是如何工作的。

PART2:ViewModel如何保存状态
我们先由上至下阅读,先从顶部的结构一直到底部,最后再对涉及到的角色进行一个总结
SavedStateRegistryController
在ComponentActivity中会调用Controller的performRestore和performSave方法:
具体看看实现:
这些Controller可以说是SavedStateRegistry的外观,它持有LifecycleOwner和Registry的实例:
并且具体的操作也依托着Registry的
同名方法。下面我们看看Registry中的perform方法的实现
SavedStateRegistry
看看其中的两个perform方法:
performRestore的逻辑还算简单,就是将Key所对应的内容读取到mRestoredState这个Bundle中。performSave的逻辑总结而言就是将Map中的SavedStateProvider和mRestoreState都存在了mBundle中。我们在SavedStateHandle中还会见到SavedStateProvider发挥它的作用,所以说到的时候再具体说。

所以这块的逻辑是这样,当onCreate调用时,会执行performRestore,将Bundle中的数据寸在SavedStateRegistry的Bundle mRestoreState中;当执行onSaveInstanceState时,会从Bundle mRestoreState中读取数据,具体怎么读的,怎么使用的Bundle中的数据的,还记得SavedStateHandle吗,就是存放在ViewModel中的那个,现在我们来看看:
SavedStateHandle
我们先回顾一下构建ViewModel的逻辑时的图:

在Factory的create方法的调用链上还调用了SavedStateHandleController#attachToLifecycle方法:
这个方法除了做了生命周期的操作之外,还将Provider注册到了SaveStateRegistry中。我们现在来看SavedStateHandle中的Provider的实现:

所以返回的Bundle中是一个ArrayList<String>和ArrayList<Object>的结构。
这里其实我没分析特别明白,我不知道这部分的Provider绑定到ViewModel之后如何取出数据的,而且官方文档中也没说清楚。

我们看看官方给出的使用ViewModel保存状态的例子中是如何使用到这些结构的。
直接使用SavedStateHandle保存数据
数据在进程终止时会保存下来。SavedStateHandle会将结果存在mRegular中,如果Activity被销毁,就回调用onSaveInstanceState->SavedStateRegistry#performSave->Provider#saveState获取到对应的数据。在SavedStateProvider#saveState是将键名和值,使用put方法放入Bundle。
通过写SavedStateProvider
在官方的例子中,如果我们想要使用保存状态的功能,分成以下几步:
定义Provider
将Provider注册到SavedStateRegistry
其实这个写法和上面的相似,但是因为在创建ViewModel的时候,尤其是使用by viewModels时,会自动创建SavedStateHandle。我们在自定义的Provider中实现saveState方法,在onSaveInstanceState时,也会通过SavedStateRegistry#performSave调用。进而也会保存在Bundle中
总结
虽然写了这么多,但是其实我个人其实对于ViewModel的状态保存还不是特别理解。根据我个人的理解,SavedState相关的几个类的关系如下:

ViewModel的创建通过ViewModelProvider实现,主要通过ViewModelStore和Factory这样两个重要的角色。首先会从缓存中找是否存在ViewModel,如果没有在调用SavedStateViewModelFactory#create构建新的ViewModel。而且ViewModel的生命周期很长,通过Lifecycle回调进行监听,如果是onDestroy,就回调用ViewModel#onClear。
ViewModel实现状态的保存有赖于SavedStateHandle及其内部的SavedStateProvider实现。当Activity要被销毁时,调用SavedStateRegistry#performSave就会调用系统默认注册的SavedStateHandle中的Provider,保存数据。
用户可以通过传入SavedStateHandle(在Factory#create中反射调用了一个具有SaveStateHandle的构造方法,这个方法在ViewModel中是没有的)实现保存状态;也可以实现Provider,两者的原理大体相同。
鉴于我对于状态保存还理解不深入,之后遇到开发问题再过来补充!