读完这篇文章,你会知道什么?
- 为什么
ViewModel#onClear
执行在Activity#onDestory
之前,但生命周期比Activity
长 LifecycleObserver
是如何兼容LifecycleEventObserver
和DefaultLifecycleObserver
SavedStateRegistry
工作机制和涉及每个类的职责ViewModel
创建过程中涉及每个类的职责SavedStateHandle
作用及两种创建过程的差异rememberSaveable
状态存储过程中涉及每个类的职责Compose NavHost
是如何自定义LifecycleOwner
、ViewModelStoreOwner
、SavedStateRegistryOwner
、SaveableStateRegistry
Lifecycle 组件
相关成员
LifecycleOwner
:Lifecycle
的所有者,用于提供Lifecycle
LifecycleRegistry
: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
: 需要实现onStateChanged
DefaultLifecycleObserver
:需要实现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
相关成员
SavedStateRegistryController
SavedStateRegistry
SavedStateRegistryOwner
SavedStateRegistryController
职责
performAttch
: 注入Recreator
和执行SavedStateRegistry#performAttch
performRestore
调用SavedStateRegistry#performRestore
performSave
调用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
存储和恢复机制的;
最后
如果想要成为架构师或想突破20~30K薪资范畴,那就不要局限在编码,业务,要会选型、扩展,提升编程思维。此外,良好的职业规划也很重要,学习的习惯很重要,但是最重要的还是要能持之以恒,任何不能坚持落实的计划都是空谈。
如果你没有方向,这里给大家分享一套由阿里高级架构师编写的《Android八大模块进阶笔记》,帮大家将杂乱、零散、碎片化的知识进行体系化的整理,让大家系统而高效地掌握Android开发的各个知识点。
相对于我们平时看的碎片化内容,这份笔记的知识点更系统化,更容易理解和记忆,是严格按照知识体系编排的。
全套视频资料:
一、面试合集
二、源码解析合集
三、开源框架合集
欢迎大家一键三连支持,若需要文中资料,直接扫描文末CSDN官方认证微信卡片免费领取↓↓↓
PS:群里还设有ChatGPT机器人,可以解答大家在工作上或者是技术上的问题