系列文章
【背上Jetpack】Jetpack 主要组件的依赖及传递关系
【背上Jetpack】AdroidX下使用Activity和Fragment的变化
【背上Jetpack之Fragment】你真的会用Fragment吗?Fragment常见问题以及androidx下Fragment的使用新姿势
【背上Jetpack之Fragment】从源码角度看 Fragment 生命周期 AndroidX Fragment1.2.2源码分析
前言
大家都知道 activity 有着一套
onSaveInstanceState-onRestoreInstanceState
状态保存机制,旨在「系统资源回收」或「配置发生变化」保存状态,为用户提供更好的体验在 androidx 下,提供了 SavedState 库帮助 activity 和 fragment 处理状态保存和恢复
本文默认您对状态保存机制有一定了解,这部分内容请移步 Saving UI States
此外,关于 android 下的进程管理,推荐 Ian Lake 的 Who lives and who dies? Process priorities on Android
本文介绍了 androidx 下 SavedState
如何帮助 activity 和 fragment 处理状态的保存和恢复,同时介绍 viewmodel-savedstate
库,以及在开发过程中正确使用状态保存的姿势
软件工程中没有什么是中间层解决不了的
在分析 SavedState 库之前我们需要简单聊一聊 ComponentActivity
androidx activity 1.0.0 时,ComponentActivity
成为了 FragmentActivity
和 AppCompatActivity
的基类。
俗话说「百因必有果」,带着强烈的好奇心,我查了一下 ComponentActivity
引入的原因。
可以看到 ComponentActivity
继承了 androidx.core.app.ComponentActivity(在 fragment 库中),并且最初仅实现了LifecycleOwner
接口
我们创建的 activity 的继承关系现在变成了这样:
那么回到最初的问题,为什么要引入 ComponentActivity
?其实看看现在 ComponentActivity
的类结构答案就很清楚了
ComponentActivity
实现了五个接口,代表着其除了 activity 还充当着五种角色。本着职能单一原则,官方通过建立一个中间层将部分功能分别交于专门的类来负责,OnBackPressedDispatcherOwner
就是我们讲 fragment 返回栈(【背上Jetpack之OnBackPressedDispatcher】Fragment 返回栈预备篇)时提到的结构,而其中的 SavedStateRegistryOwner
则是我们今天要讲的主角 SavedState 中的成员
SavedState
引入 SavedState
implementation "androidx.savedstate:savedstate:1.0.0"
其实您不需要显示地声明,因为 activity 库内部已经引入了。jetpack 组件依赖关系可参考 【背上Jetpack】Jetpack 主要组件的依赖及传递关系
这是一个很小的库
SavedStateProvider
保存状态的组件,此状态将在以后恢复并使用
public interface SavedStateProvider {
@NonNull
Bundle saveState();
}
SavedStateRegistry
管理 SavedStateProvider
列表的组件,此注册表绑定了其所有者的生命周期(即 activity 或 fragment)。每次创建生命周期所有者都会创建一个新的实例
创建注册表的所有者后(例如,在调用 activity 的 onCreate(savedInstanceState)
方法之后),将调用其 performRestore(state)
方法,以恢复系统杀死其所有者之前保存的任何状态。
void performRestore(@NonNull Lifecycle lifecycle, @Nullable Bundle savedState) {
// ...
if (savedState != null) {
mRestoredState = savedState.getBundle(SAVED_COMPONENTS_KEY);
}
// ...
}
每个注册表的 SavedStateProvider
都由用于注册它的唯一密钥标识
private SafeIterableMap<String, SavedStateProvider> mComponents = new SafeIterableMap<>();
public void registerSavedStateProvider(@NonNull String key, @NonNull SavedStateProvider provider) {
SavedStateProvider previous = mComponents.putIfAbsent(key, provider);
if (previous != null) {
throw new IllegalArgumentException("SavedStateProvider with the given key is already registered");
}
}