一文搞懂Android jetpack 状态存储

读完这篇文章,你会知道什么?

  1. 为什么 ViewModel#onClear 执行在 Activity#onDestory 之前,但生命周期比 Activity
  2. LifecycleObserver 是如何兼容 LifecycleEventObserverDefaultLifecycleObserver
  3. SavedStateRegistry 工作机制和涉及每个类的职责
  4. ViewModel 创建过程中涉及每个类的职责
  5. SavedStateHandle 作用及两种创建过程的差异
  6. rememberSaveable 状态存储过程中涉及每个类的职责
  7. Compose NavHost 是如何自定义 LifecycleOwnerViewModelStoreOwnerSavedStateRegistryOwnerSaveableStateRegistry

Lifecycle 组件

相关成员

  1. LifecycleOwner: Lifecycle 的所有者,用于提供 Lifecycle
  2. LifecycleRegistry: Lifecycle 的子类,可以直接使用从而快速自定义生命周期管理和监听分发
  3. LifecycleObserver: 生命周期观察者, 用于监听生命周期的变化,默认子类有 LifecycleEventObserverDefaultLifecycleObserver
  • Tips: ComponentActivity 使用 ReportFragment 调用 LifecycleRegistry 分发自身生命周期

疑问:

  1. ViewModel#onClear 的执行是在 Activity#preDestory 的时候调用,为什么说 ViewModel 的生命周期比 Activity
  1. ViewModel#onClear 执行的时候,会判断是否由于配置改变导致的 Activity 销毁,如果不是则执行 ViewModel#onClear;如果是的话,则不执行 ViewModel 的清理工作
  2. 在因配置修改导致 Activity 重启的时候,会存储当前 ComponentActivity#ViewModelStoreActivityThread#ActivityClientRecord#lastNonConfigurationInstances
  • 调用链: ActivityThread#performDestroyActivity -> Activity#retainNonConfigurationInstances -> ComponentActivity#onRetainNonConfigurationInstance
  • ComponentActivity#onRetainNonConfigurationInstance 方法可知,ComponentActivity子类 可重写 onRetainCustomNonConfigurationInstance 方法来持有 不因配置修改的状态;不过已经被废弃,使用 ViewModel 来存储 不因配置修改的状态
  1. 在因配置改变重启 原Activity 的时候,ActivityThread#performLaunchActivity 会调用 activity#attch 同时会携带上次保存的 Activity#NonConfigurationInstances 状态
  2. 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;  
}

  1. 为什么 LifecycleObserver 没有任何方法定义

LifecycleObserver 没有任何实现,是因为原先使用方式是 自定义方法 加上 对应生命周期注解 使用的,在 androidx.lifecycle-*:2.4.0 被废弃了,所以是没有任何方法定义

class CustomLifecycleObserver : LifecycleObserver {
    @@OnLifecycleEvent(Lifecycle.Event.ON_STOP)  
    fun onStop() {
        // ...
    }
}

  1. 系统是如何实现注入 LifecycleEventObserver 或者 DefaultLifecycleObserver 都可以正常收取对应到回调
  • LifecycleEventObserver: 需要实现 onStateChanged
  • DefaultLifecycleObserver:需要实现 onCreateonStartonResumeonPauseonStoponDestory
  • 通过 LifecycleRegistry#addObserver 可知,传入的 observer 会通过 Lifecycling.lifecycleEventObserver 最终还是转换为 LifecycleEventObserver; 可以看到本质还是通过LifecycleEventObserver 的方法转换调用 DefaultLifecycleObserveronCreate 等方法
  • 同时由 FullLifecycleObserverAdapter 可知, 如果 Observer 同时实现 LifecycleEventObserverDefaultLifecycleObserver 都会调用对应的回调
  1. 生命周期是 跳动式 的还是 递进式
  • LifecycleRegistrybackwardPassforwardPass 可知,状态是一级一级的递进,而不是突然跳动

SavedStateRegistryOwner

  • androidX 基于 ActivityonSaveInstanceStateonCreate 封装的一套API,可以在需要存储数据的时候执行 SavedStateRegistry#performSave,在需要恢复数据的时候执行 SavedStateRegistry#performRestore
  • 其中存储的数据需要支持序列化 Parcelable

相关成员

  1. SavedStateRegistryController
  2. SavedStateRegistry
  3. SavedStateRegistryOwner

SavedStateRegistryController 职责

  1. performAttch: 注入 Recreator 和执行 SavedStateRegistry#performAttch
  2. performRestore 调用 SavedStateRegistry#performRestore
  3. performSave 调用 SavedStateRegistry#performSave

Recreator 职责

  1. 用于保存 SavedStateRegistry#AutoRecreated 的集合
  2. 在恢复的时候,自动创建和调用 SavedStateRegistry#AutoRecreated 的集合

SavedStateRegistry 职责

  1. SavedStateProvider 用于提供如何保存状态的接口
  2. SavedStateRegistry 被重启的时候,会自动创建已加入 AutoRecreated 集合相关的类; 通过 SavedStateRegistry#runOnNextRecreation 添加到自动创建列表中
  3. 存储和恢复相关方法: performSave(保存存储状态) 和 performRestore(获得存储状态)
  4. 通过 registerSavedStateProviderunregisterSavedStateProvider 键值对方式管理 SavedStateProvider
  5. 通过 consumeRestoredStateForKey 获取 存储的状态信息

ComponentActivitySavedStateRegistry 交互代码

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);
    }
}

疑问:

  1. 为什么不使用 onSaveInstanceState 对应的 onRestoreInstanceState 来执行恢复,而使用 onCreate?

猜测: onRestoreInstanceStateframework 在第一次分发 onStart 的时候执行; onSaveInstanceStateframework 每次分发 onPause 的时候执行保存状态; 在 onCreate 执行恢复, 猜测是为了更早的恢复,源码内置了挺多根据生命周期 onCreate 消费恢复数据的

  • Tips: 其中状态都是从 ActivityClientRecord#state 上获取

SavedStateHandle - ViewModel 的状态存储和恢复工具

  • SavedStateHandle 最后也是挂载 SavedStateRegistry 上实现状态存储和恢复的,所以也是需要存储的内容是可以被序列化的

ViewModel 创建的相关类

  1. ViewModelStore: 用于存放 ViewModel 实例
  2. ViewModelProvider.Factory: 负责如何创建 ViewModel 实例
  3. ViewModelProvider: 负责控制 ViewModelStoreViewModelProvider.Factory 的执行流程
  4. CreationExtra: 可以携带 ViewModel 创建参数,需要与 ViewModelProvider.Factory 配合使用
  5. HasDefaultViewModelProviderFactory: 在使用 ViewModelStoreOwner 创建 ViewModelProvider 的时候,如果当前 owner 属于 HasDefaultViewModelProviderFactory 实现,则会从中提取默认的 ViewModelProvider.FactoryCreationExtra;
  • 因为 androidx.activity.ComponentActivity 实现 HasDefaultViewModelProviderFactory,所以使用 ViewModelProvider(this) 是可以创建出带 SavedStateHandleViewModel
  • 其实能从 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种创建方式
  1. 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()
    }
}

  1. LegacySavedStateHandleController 方式创建,由对应的 ViewModel 持有 Controller, 此 Controller 主要是用于挂载 SavedStateRegistry装载恢复数据
  • Tips:因为 ViewModel 持有 LegacySavedStateHandleController, 所以在 界面配置修改,会进行界面重启;但此时 ViewModel 已经生成,所以内部实现了 SavedStateRegistry.AutoRecreated 用于在这种情况将 SavedStateHandle 重新挂载到 SavedStateRegistry

疑问

  1. 默认 ViewModel#key 怎么决定的

默认由 ViewModelProvider#get 方法决定, 值为 androidx.lifecycle.ViewModelProvider.DefaultKey:${modelClass.canonicalName}, 也可以调用双参数的方法进行自定义 key 传入

  1. SavedStateHandle#savedStateProvidersavedStateRegistry 中的注册的 key 是什么

是使用 ViewModel#key 注册的,在默认情况下,重启恢复 key 也不会发生改变,从而可以正确恢复状态

  1. ViewModelSavedStateHandle 的关系

ViewModelSavedStateHandle 是一对一的关系;默认是使用 ViewModel#keysavedStateRegistry 注册 SavedStateProvider 用于保存数据和恢复数据的

  1. 2种创建 SavedStateHandle 有什么差异
  • 对于使用方来说, 2种创建得到 SavedStateHandle 使用方式是完全一致的;
  • 我翻了一下 ViewModel-SavedState 库的历史记录,发现 LegacySavedStateHandleController 是最开始创建 SavedStateHandle 的一套;
  • 而通过 CreationExtras.createSavedStateHandle 创建 SavedStateHandle 是中途新加入的一种创建方式;
  • 二种方式共存应该是兼容新老版本的交替使用

SaveableStateRegistry(Compose的状态存储)

DisposableSaveableStateRegistry 职责

  1. 挂载到 Android Lifecycle SavedStateRegistry 上,调用 SaveableStateRegistry#performSave 存储和 带恢复数据创建 SaveableStateRegistry
  2. 扩展 SaveableStateRegistry 功能,增加 onDispose 方法,取消 Android Lifecycle SavedStateRegistry 注册

SaveableStateRegistry 职责

  1. canBeSaved: (Any) -> Boolean : 判断检查存储对象是否合法
  2. consumeRestored: 消耗恢复数据
  3. registerProvider + Entry: 注册和反注册存储回调,一次注册 [key] -> [() -> Any?]
  4. performSave: 存储当前已注册的 Provider已恢复未消耗的数据

rememberSaveable 职责

  1. 执行 SaveableStateRegistry#consumeRestored 消耗缓存数据
  2. 进入的时候调用 SaveableStateRegistry 注册,在离开界面的时候进行 SaveableStateRegistry 反注册

Saver 职责

  1. 用于从 SaveableStateRegistry 恢复的数据转换成 业务数据
  2. 用于 业务数据 转成可被 SaveableStateRegistry 恢复存储的 数据
  • Tips: 存储的时候携带 SaverScope 是可以用来调用 SaveableStateRegistry#canBeSaved,判断对象是否可以被保存
  • Saver 相关衍生对象有三个:
  1. listSaver: 把 对象 拆分成 list, 然后把 list 转换成 对象
  2. autoSaver: saver 的默认实现,不会做任何转换
  3. mapSaver: 把 对象 拆分成 map, 然后把 map 转换成 对象,底层使用 listSaver 实现

疑问

  1. 恢复是指定 key 对应一个 List<Any?>, 但注册是一个 key 对应一个 () -> Any?

答: 在 Composable 可能会同时取相同的 key,按照先后顺序,可以确定所需要的位置,因为只有 rememberSaveable 能消费,除非开发者自定义导致异常,不然一般不会出现问题

Composable - NavHost 自定义 owner

自定义 NavBackStackEntry#LifecycleOwner

  • 当前生命周期 = Math.min(外部生命周期, 内部生命周期)
  • 外部生命周期 监听外部 Lifecyle 可得
  • 内部生命周期NavController 分发可得

自定义 NavBackStackEntry#ViewModelStoreOwner

  1. 使用外部 ViewModelStore 创建一个 NavControllerViewModelkeyandroidx.lifecycle.ViewModelProvider.DefaultKey:${modelClass.canonicalName},则 ViewModelStore 不变的情况先,每次获取的 NavControllerViewModel 为同一个
  2. 在创建 NavBackStackEntry 的时候,会传入 NavControllerViewModel 实例
  3. 获取 NavBackStackEntry#viewModelStore 的时候,会从 NavControllerViewModel 加上自身 NavBackStackEntry#id[UUID] 获取到对应 ViewModelStore, UUID不变则获取的 ViewModelStore 也不变
  • Tips: NavControllerViewModel 自身即是 ViewModel 也是 NavViewModelStoreProvider, 用于提供 ViewModelStore 和管理已提供的 ViewModelStore

自定义 NavBackStackEntry#SavedStateRegistryOwner

  1. NavBackStackEntry 执行初次更新生命周期的时候执行 savedStateRegistryController#performAttachsavedStateRegistryController#performRestore 用于挂载和恢复savedStateRegistry
  2. 在每次 NavBackStackEntry 存储状态的时候,会调用自身 NavBackStackEntry#saveState 用于存储自身 SavedStateRegistry 状态

自定义 NavBackStackEntry#SaveableStateRegistry

  1. 使用 rememberSaveableStateHolder 创建 SaveableStateHolder,同时 SaveableStateHolder#parentSaveableStateRegistry 会赋值为LocalSaveableStateRegistry.current
  2. 利用 NavBackStackEntry#ViewModelStoreOwner创建一个 BackStackEntryIdViewModel, 用于提供 唯一idonCleared 方法移除当前状态、弱引用 SaveableStateHolder
  3. 使用 唯一id子Composable 生成一个 RegistryHolder, 用于控制内部 SaveableStateRegistry 的存储和数据恢复
  4. 使用 RegistryHolder#registry子Composable 提供新的 LocalSaveableStateRegistry 的环境
  5. DisposableEffect#进入组合 移除状态(已恢复了)添加RegistryHolder, DisposableEffect#onDispose 存储状态移除RegistryHodler
疑问
  1. ViewModel#onClearDisposableEffect 都有做清除操作,区别是什么

答: SaveableStateHolder的生命周期是附属于父的SaveableStateRegistry; ViewModel#onClear 是界面退出的时候调用,所以从弱引用获取 saveableStateHolderRef 移除自身状态,不用在保存和恢复;而 DisposbaleEffect 是每次进入组合都会执行,所以在进入组合的时候提取状态,退出组合保存状态;

自定义 SavedStateHandle: 可能是用于 NavBackStackEntry 自身数据存储和恢复

  1. NavResultSavedStateFactoryNavBackStackEntry#ViewModelStore 生成 SavedStateViewModel
  2. SavedStateViewModel 获取 handle

NavHost

  1. 获取当前 LifecycleOwner, 设置 LifecycleObserver, 用于分发当前生命周期到 NavController#backQueue
  2. 设置当前 ViewModelStore, 生成一个 NavControllerViewModel
  3. 使用当前 NavBackStackEntry子Composable 提供 LifecycleOwnerViewModelStoreOwnerSavedStateRegistryOwner 环境, 使用创建的 SaveableStateHandler 提供 SaveableStateRegistry
  • Tips: SaveableStateHandler 是存储在 SaveableStateRegistry,并提供 SaveableStateRegistry
  • Tips: NavControllerViewModel 使用父环境的 ViewModelStore 存储,根据 BackStackEntry#id 生成对应的 ViewModelStore
  • Tips: NavBackStackEntry 实现 SavedStateRegistry, 可以恢复和存储数据

总结

ViewModel#SavedStateHandleCompose#SaveableStateRegistry 来看,可见状态存储和恢复本质还是依托 SavedStateRegistry, 而 SavedStateRegistry 又是依托 Activity 自身的 onSaveInstanceState 存储和恢复机制的;

最后

如果想要成为架构师或想突破20~30K薪资范畴,那就不要局限在编码,业务,要会选型、扩展,提升编程思维。此外,良好的职业规划也很重要,学习的习惯很重要,但是最重要的还是要能持之以恒,任何不能坚持落实的计划都是空谈。

如果你没有方向,这里给大家分享一套由阿里高级架构师编写的《Android八大模块进阶笔记》,帮大家将杂乱、零散、碎片化的知识进行体系化的整理,让大家系统而高效地掌握Android开发的各个知识点。
在这里插入图片描述
相对于我们平时看的碎片化内容,这份笔记的知识点更系统化,更容易理解和记忆,是严格按照知识体系编排的。

全套视频资料:

一、面试合集

在这里插入图片描述
二、源码解析合集
在这里插入图片描述

三、开源框架合集
在这里插入图片描述
欢迎大家一键三连支持,若需要文中资料,直接扫描文末CSDN官方认证微信卡片免费领取↓↓↓

PS:群里还设有ChatGPT机器人,可以解答大家在工作上或者是技术上的问题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值