读完这篇文章,你会知道什么?
- 为什么
ViewModel#onClear执行在Activity#onDestory之前,但生命周期比Activity长 LifecycleObserver是如何兼容LifecycleEventObserver和DefaultLifecycleObserverSavedStateRegistry工作机制和涉及每个类的职责ViewModel创建过程中涉及每个类的职责SavedStateHandle作用及两种创建过程的差异rememberSaveable状态存储过程中涉及每个类的职责Compose NavHost是如何自定义LifecycleOwner、ViewModelStoreOwner、SavedStateRegistryOwner、SaveableStateRegistry
Lifecycle 组件
相关成员
LifecycleOwner:Lifecycle的所有者,用于提供LifecycleLifecycleRegistry:Lifecycle的子类,可以直接使用从而快速自定义生命周期管理和监听分发LifecycleObserver: 生命周期观察者, 用于监听生命周期的变化,默认子类有LifecycleEventObserver和DefaultLifecycleObserver
- Tips:
ComponentActivity使用ReportFragment调用LifecycleRegistry分发自身生命周期
疑问:
ViewModel#onClear的执行是在Activity#preDestory的时候调用,为什么说ViewModel的生命周期比Activity长
- 在
ViewModel#onClear执行的时候,会判断是否由于配置改变导致的Activity销毁,如果不是则执行ViewModel#onClear;如果是的话,则不执行ViewModel的清理工作- 在因配置修改导致
Activity重启的时候,会存储当前ComponentActivity#ViewModelStore到ActivityThread#ActivityClientRecord#lastNonConfigurationInstances上
- 调用链:
ActivityThread#performDestroyActivity->Activity#retainNonConfigurationInstances->ComponentActivity#onRetainNonConfigurationInstance- 在
ComponentActivity#onRetainNonConfigurationInstance方法可知,ComponentActivity子类可重写onRetainCustomNonConfigurationInstance方法来持有 不因配置修改的状态;不过已经被废弃,使用ViewModel来存储 不因配置修改的状态
- 在因配置改变重启
原Activity的时候,ActivityThread#performLaunchActivity会调用activity#attch同时会携带上次保存的Activity#NonConfigurationInstances状态- 在
ComponentActivity#getViewModelStore中,会先Activity#NonConfigurationInstances#activity字段获取到ComponentActivity#NonConfigurationInstances#viewModelStore,从而恢复重启之前的ViewModel数据相关类
// Activity static final class NonConfigurationInstances { Object activity; // 一般为ComponentActivity#NonConfigurationInstances HashMap<String, Object> children; FragmentManagerNonConfig fragments; ArrayMap<String, LoaderManager> loaders; VoiceInteractor voiceInteractor; }// ComponentActivity下 static final class NonConfigurationInstances { // 可以重写 ComponentActivity#onRetainCustomNonConfigurationInstance 注入 Object custom; // 存储了ComponentActivity#ViewModelStore ViewModelStore viewModelStore; }
- 为什么
LifecycleObserver没有任何方法定义
LifecycleObserver没有任何实现,是因为原先使用方式是自定义方法加上对应生命周期注解使用的,在androidx.lifecycle-*:2.4.0被废弃了,所以是没有任何方法定义class CustomLifecycleObserver : LifecycleObserver { @@OnLifecycleEvent(Lifecycle.Event.ON_STOP) fun onStop() { // ... } }
- 系统是如何实现注入
LifecycleEventObserver或者DefaultLifecycleObserver都可以正常收取对应到回调
LifecycleEventObserver: 需要实现onStateChangedDefaultLifecycleObserver:需要实现onCreate、onStart、onResume、onPause、onStop、onDestory- 通过
LifecycleRegistry#addObserver可知,传入的observer会通过Lifecycling.lifecycleEventObserver最终还是转换为LifecycleEventObserver; 可以看到本质还是通过LifecycleEventObserver的方法转换调用DefaultLifecycleObserver的onCreate等方法- 同时由
FullLifecycleObserverAdapter可知, 如果Observer同时实现LifecycleEventObserver和DefaultLifecycleObserver都会调用对应的回调
- 生命周期是
跳动式的还是递进式
- 由
LifecycleRegistry的backwardPass和forwardPass可知,状态是一级一级的递进,而不是突然跳动
SavedStateRegistryOwner
androidX基于Activity的onSaveInstanceState和onCreate封装的一套API,可以在需要存储数据的时候执行SavedStateRegistry#performSave,在需要恢复数据的时候执行SavedStateRegistry#performRestore;- 其中存储的数据需要支持序列化
Parcelable
相关成员
SavedStateRegistryControllerSavedStateRegistrySavedStateRegistryOwner
SavedStateRegistryController 职责
performAttch: 注入Recreator和执行SavedStateRegistry#performAttchperformRestore调用SavedStateRegistry#performRestoreperformSave调用SavedStateRegistry#performSave
Recreator 职责
- 用于保存
SavedStateRegistry#AutoRecreated的集合 - 在恢复的时候,自动创建和调用
SavedStateRegistry#AutoRecreated的集合
SavedStateRegistry 职责
SavedStateProvider用于提供如何保存状态的接口- 在
SavedStateRegistry被重启的时候,会自动创建已加入AutoRecreated集合相关的类; 通过SavedStateRegistry#runOnNextRecreation添加到自动创建列表中 - 存储和恢复相关方法:
performSave(保存存储状态) 和performRestore(获得存储状态) - 通过
registerSavedStateProvider和unregisterSavedStateProvider键值对方式管理SavedStateProvider - 通过
consumeRestoredStateForKey获取 存储的状态信息
ComponentActivity 与 SavedStateRegistry 交互代码
public class ComponentActivity {
// ..
public ComponentActivity() {
// ...
mSavedStateRegistryController.performAttach(); // 关联
// ..
}
// ..
protected void onCreate(@Nullable Bundle savedInstanceState) {
// ...
// 恢复数据到 SavedStateRegistry
mSavedStateRegistryController.performRestore(savedInstanceState);
// ..
}
protected void onSaveInstanceState(@NonNull Bundle outState) {
// ..
// 存储当前状态 - 每次 onPause 事件发生的时候执行
mSavedStateRegistryController.performSave(outState);
}
}
疑问:
- 为什么不使用
onSaveInstanceState对应的onRestoreInstanceState来执行恢复,而使用 onCreate?
猜测:
onRestoreInstanceState在framework在第一次分发onStart的时候执行;onSaveInstanceState在framework每次分发onPause的时候执行保存状态; 在onCreate执行恢复, 猜测是为了更早的恢复,源码内置了挺多根据生命周期onCreate消费恢复数据的
- Tips: 其中状态都是从
ActivityClientRecord#state上获取
SavedStateHandle - ViewModel 的状态存储和恢复工具
SavedStateHandle最后也是挂载SavedStateRegistry上实现状态存储和恢复的,所以也是需要存储的内容是可以被序列化的
ViewModel 创建的相关类
ViewModelStore: 用于存放ViewModel实例ViewModelProvider.Factory: 负责如何创建ViewModel实例ViewModelProvider: 负责控制ViewModelStore和ViewModelProvider.Factory的执行流程CreationExtra: 可以携带ViewModel创建参数,需要与ViewModelProvider.Factory配合使用HasDefaultViewModelProviderFactory: 在使用ViewModelStoreOwner创建ViewModelProvider的时候,如果当前owner属于HasDefaultViewModelProviderFactory实现,则会从中提取默认的ViewModelProvider.Factory和CreationExtra;
- 因为
androidx.activity.ComponentActivity实现HasDefaultViewModelProviderFactory,所以使用ViewModelProvider(this)是可以创建出带SavedStateHandle的ViewModel - 其实能从
ComponentActivity#getDefaultViewModelCreationExtras的实现可知,根据键值对的方式注入了一些常用参数
// androidx.activity.ComponentActivity 的实现
public CreationExtras getDefaultViewModelCreationExtras() {
MutableCreationExtras extras = new MutableCreationExtras();
if (getApplication() != null) {
extras.set(ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY, getApplication());
}
extras.set(SavedStateHandleSupport.SAVED_STATE_REGISTRY_OWNER_KEY, this);
extras.set(SavedStateHandleSupport.VIEW_MODEL_STORE_OWNER_KEY, this);
if (getIntent() != null && getIntent().getExtras() != null) {
extras.set(SavedStateHandleSupport.DEFAULT_ARGS_KEY, getIntent().getExtras());
}
return extras;
}
SavedStateHandle
- 由
AbstractSavedStateViewModelFactory源码可知,SavedStateHandle有2种创建方式
SavedStateHandleSupport#createSavedStateHandle创建方式;会创建一个SavedStateHandlesProvider专门管理SavedStateHandle存储和恢复,同时在创建SavedStateHandlesProvider的时候会自动挂载SavedStateRegistry身上和装载恢复的数据
// 在构造函数的时候的时候调用, 创建 SavedStateHandlesProvider
fun <T> T.enableSavedStateHandles()
where T : SavedStateRegistryOwner, T : ViewModelStoreOwner {
val currentState = lifecycle.currentState
require(
currentState == Lifecycle.State.INITIALIZED || currentState == Lifecycle.State.CREATED
)
if (savedStateRegistry.getSavedStateProvider(SAVED_STATE_KEY) == null) {
val provider = SavedStateHandlesProvider(savedStateRegistry, this)
// 将 SavedStateHandlesProvider 注册到 savedStateRegistry
savedStateRegistry.registerSavedStateProvider(SAVED_STATE_KEY, provider)
lifecycle.addObserver(SavedStateHandleAttacher(provider))
}
}
internal class SavedStateHandleAttacher(
private val provider: SavedStateHandlesProvider
) : LifecycleEventObserver {
override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
check(event == Lifecycle.Event.ON_CREATE) {
"Next event must be ON_CREATE, it was $event"
}
source.lifecycle.removeObserver(this)
// 恢复数据
provider.performRestore()
}
}
- 由
LegacySavedStateHandleController方式创建,由对应的ViewModel持有Controller, 此Controller主要是用于挂载SavedStateRegistry和装载恢复数据
- Tips:因为
ViewModel持有LegacySavedStateHandleController, 所以在界面配置修改,会进行界面重启;但此时ViewModel已经生成,所以内部实现了SavedStateRegistry.AutoRecreated用于在这种情况将SavedStateHandle重新挂载到SavedStateRegistry上
疑问
- 默认
ViewModel#key怎么决定的
默认由
ViewModelProvider#get方法决定, 值为androidx.lifecycle.ViewModelProvider.DefaultKey:${modelClass.canonicalName}, 也可以调用双参数的方法进行自定义key传入
SavedStateHandle#savedStateProvider在savedStateRegistry中的注册的key是什么
是使用
ViewModel#key注册的,在默认情况下,重启恢复key也不会发生改变,从而可以正确恢复状态
ViewModel和SavedStateHandle的关系
ViewModel和SavedStateHandle是一对一的关系;默认是使用ViewModel#key在savedStateRegistry注册SavedStateProvider用于保存数据和恢复数据的
- 2种创建
SavedStateHandle有什么差异
- 对于使用方来说, 2种创建得到
SavedStateHandle使用方式是完全一致的;- 我翻了一下 ViewModel-SavedState 库的历史记录,发现
LegacySavedStateHandleController是最开始创建SavedStateHandle的一套;- 而通过
CreationExtras.createSavedStateHandle创建SavedStateHandle是中途新加入的一种创建方式;- 二种方式共存
应该是兼容新老版本的交替使用
SaveableStateRegistry(Compose的状态存储)
DisposableSaveableStateRegistry 职责
- 挂载到
Android Lifecycle SavedStateRegistry上,调用SaveableStateRegistry#performSave存储和 带恢复数据创建SaveableStateRegistry - 扩展
SaveableStateRegistry功能,增加onDispose方法,取消Android Lifecycle SavedStateRegistry注册
SaveableStateRegistry 职责
canBeSaved: (Any) -> Boolean: 判断检查存储对象是否合法consumeRestored: 消耗恢复数据registerProvider+Entry: 注册和反注册存储回调,一次注册[key] -> [() -> Any?]performSave: 存储当前已注册的Provider和 已恢复未消耗的数据
rememberSaveable 职责
- 执行
SaveableStateRegistry#consumeRestored消耗缓存数据 - 进入的时候调用
SaveableStateRegistry注册,在离开界面的时候进行SaveableStateRegistry反注册
Saver 职责
- 用于从
SaveableStateRegistry恢复的数据转换成 业务数据 - 用于 业务数据 转成可被
SaveableStateRegistry恢复存储的 数据
- Tips: 存储的时候携带
SaverScope是可以用来调用SaveableStateRegistry#canBeSaved,判断对象是否可以被保存 Saver相关衍生对象有三个:
listSaver: 把 对象 拆分成list, 然后把list转换成 对象autoSaver:saver的默认实现,不会做任何转换mapSaver: 把 对象 拆分成map, 然后把map转换成 对象,底层使用listSaver实现
疑问
- 恢复是指定
key对应一个List<Any?>, 但注册是一个key对应一个() -> Any?
答: 在
Composable可能会同时取相同的key,按照先后顺序,可以确定所需要的位置,因为只有rememberSaveable能消费,除非开发者自定义导致异常,不然一般不会出现问题
Composable - NavHost 自定义 owner
自定义 NavBackStackEntry#LifecycleOwner
- 当前生命周期 = Math.min(外部生命周期, 内部生命周期)
- 外部生命周期 监听外部
Lifecyle可得 - 内部生命周期 由
NavController分发可得
自定义 NavBackStackEntry#ViewModelStoreOwner
- 使用外部
ViewModelStore创建一个NavControllerViewModel,key为androidx.lifecycle.ViewModelProvider.DefaultKey:${modelClass.canonicalName},则ViewModelStore不变的情况先,每次获取的NavControllerViewModel为同一个 - 在创建
NavBackStackEntry的时候,会传入NavControllerViewModel实例 - 获取
NavBackStackEntry#viewModelStore的时候,会从NavControllerViewModel加上自身NavBackStackEntry#id[UUID]获取到对应ViewModelStore,UUID不变则获取的ViewModelStore也不变
- Tips:
NavControllerViewModel自身即是ViewModel也是NavViewModelStoreProvider, 用于提供ViewModelStore和管理已提供的ViewModelStore
自定义 NavBackStackEntry#SavedStateRegistryOwner
- 在
NavBackStackEntry执行初次更新生命周期的时候执行savedStateRegistryController#performAttach和savedStateRegistryController#performRestore用于挂载和恢复savedStateRegistry - 在每次
NavBackStackEntry存储状态的时候,会调用自身NavBackStackEntry#saveState用于存储自身SavedStateRegistry状态
自定义 NavBackStackEntry#SaveableStateRegistry
- 使用
rememberSaveableStateHolder创建SaveableStateHolder,同时SaveableStateHolder#parentSaveableStateRegistry会赋值为LocalSaveableStateRegistry.current - 利用
NavBackStackEntry#ViewModelStoreOwner创建一个BackStackEntryIdViewModel, 用于提供 唯一id、 onCleared 方法移除当前状态、弱引用SaveableStateHolder - 使用 唯一id 和 子Composable 生成一个
RegistryHolder, 用于控制内部SaveableStateRegistry的存储和数据恢复 - 使用
RegistryHolder#registry为 子Composable 提供新的LocalSaveableStateRegistry的环境 DisposableEffect#进入组合移除状态(已恢复了) 和 添加RegistryHolder,DisposableEffect#onDispose存储状态 和 移除RegistryHodler
疑问
ViewModel#onClear和DisposableEffect都有做清除操作,区别是什么
答:
SaveableStateHolder的生命周期是附属于父的SaveableStateRegistry;ViewModel#onClear是界面退出的时候调用,所以从弱引用获取saveableStateHolderRef移除自身状态,不用在保存和恢复;而DisposbaleEffect是每次进入组合都会执行,所以在进入组合的时候提取状态,退出组合保存状态;
自定义 SavedStateHandle: 可能是用于 NavBackStackEntry 自身数据存储和恢复
- 从
NavResultSavedStateFactory和NavBackStackEntry#ViewModelStore生成SavedStateViewModel - 从
SavedStateViewModel获取handle
NavHost
- 获取当前
LifecycleOwner, 设置LifecycleObserver, 用于分发当前生命周期到NavController#backQueue - 设置当前
ViewModelStore, 生成一个NavControllerViewModel - 使用当前
NavBackStackEntry为子Composable提供LifecycleOwner、ViewModelStoreOwner、SavedStateRegistryOwner环境, 使用创建的SaveableStateHandler提供SaveableStateRegistry
- Tips:
SaveableStateHandler是存储在SaveableStateRegistry,并提供SaveableStateRegistry - Tips:
NavControllerViewModel使用父环境的ViewModelStore存储,根据BackStackEntry#id生成对应的ViewModelStore - Tips:
NavBackStackEntry实现SavedStateRegistry, 可以恢复和存储数据
总结
从 ViewModel#SavedStateHandle 和 Compose#SaveableStateRegistry 来看,可见状态存储和恢复本质还是依托 SavedStateRegistry, 而 SavedStateRegistry 又是依托 Activity 自身的 onSaveInstanceState 存储和恢复机制的;