提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
Android 应用在因系统资源限制进程被杀死时可通过 onSaveInstanceState-onRestoreInstanceState 保存一些必要数据用于在页面重建时恢复页面 savedstate 对此进行了封装,它与 ViewModel 的区别:
源码分析
来看一下 onSaveInstanceState 和 onCreate 两处保存和恢复数据的地方
// androidx.activity.ComponentActivity
public class ComponentActivity extends androidx.core.app.ComponentActivity implements
SavedStateRegistryOwner {
// 静态方法创建 SavedStateRegistryController 对象
final SavedStateRegistryController mSavedStateRegistryController =
SavedStateRegistryController.create(this);
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
// 恢复数据
mSavedStateRegistryController.performRestore(savedInstanceState);
}
@CallSuper
@Override
protected void onSaveInstanceState(@NonNull Bundle outState) {
Lifecycle lifecycle = getLifecycle();
if (lifecycle instanceof LifecycleRegistry) {
((LifecycleRegistry) lifecycle).setCurrentState(Lifecycle.State.CREATED);
}
super.onSaveInstanceState(outState);
// 保存数据
mSavedStateRegistryController.performSave(outState);
}
@NonNull
@Override
public final SavedStateRegistry getSavedStateRegistry() {
return mSavedStateRegistryController.getSavedStateRegistry();
}
}
ComponentActivity 实现了 SavedStateRegistryOwner 接口重写 getSavedStateRegistry 方法返回一个 SavedStateRegistry 并且在 onCreate 和 onSaveInstanceState 中分别调用了 SavedStateRegistryController 保存和恢复数据的方法
public final class SavedStateRegistryController {
private final SavedStateRegistryOwner mOwner;
private final SavedStateRegistry mRegistry;
private SavedStateRegistryController(SavedStateRegistryOwner owner) {
mOwner = owner;
// 创建 SavedStateRegistry 对象
mRegistry = new SavedStateRegistry();
}
@NonNull
public SavedStateRegistry getSavedStateRegistry() {
// 返回 SavedStateRegistry 对象
return mRegistry;
}
@MainThread
public void performRestore(@Nullable Bundle savedState) {
Lifecycle lifecycle = mOwner.getLifecycle();
if (lifecycle.getCurrentState() != Lifecycle.State.INITIALIZED) {
throw new IllegalStateException("Restarter must be created only during "
+ "owner's initialization stage");
}
lifecycle.addObserver(new Recreator(mOwner));
// 转发给 SavedStateRegistry
mRegistry.performRestore(lifecycle, savedState);
}
@MainThread
public void performSave(@NonNull Bundle outBundle) {
// 转发给 SavedStateRegistry
mRegistry.performSave(outBundle);
}
@NonNull
public static SavedStateRegistryController create(@NonNull SavedStateRegistryOwner owner) {
return new SavedStateRegistryController(owner);
}
}
SavedStateRegistryController 就是简单的对 SavedStateRegistry的包装,在构造方法里创建了 SavedStateRegistry 对象,保存和恢复数据的方法直接转发给了 SavedStateRegistry
public final class SavedStateRegistry {
private static final String SAVED_COMPONENTS_KEY =
"androidx.lifecycle.BundlableSavedStateRegistry.key";
private SafeIterableMap<String, SavedStateProvider> mComponents =
new SafeIterableMap<>();
@Nullable
private Bundle mRestoredState;
private boolean mRestored;
private Recreator.SavedStateProvider mRecreatorProvider;
boolean mAllowingSavingState = true;
SavedStateRegistry() {
}
@MainThread
@Nullable
// 根据 key 取出在组件被杀死时保存的数据
public Bundle consumeRestoredStateForKey(@NonNull String key) {
// 在数据恢复前消费抛出异常
if (!mRestored) {
throw new IllegalStateException("You can consumeRestoredStateForKey "
+ "only after su
+ per.onCreate of corresponding component");
}
// 如果恢复的数据不为空
if (mRestoredState != null) {
// 根据 key 取出保存的数据
Bundle result = mRestoredState.getBundle(key);
// 取出后就移除第二次再取就返回 null 了
mRestoredState.remove(key);
// 如果全部取出则置为 null
if (mRestoredState.isEmpty()) {
mRestoredState = null;
}
return result;
}
return null;
}
@MainThread
// 注册要在组件被杀死时保存数据的来源
public void registerSavedStateProvider(@NonNull String key,
@NonNull SavedStateProvider provider) {
// 保存到 map 中
SavedStateProvider previous = mComponents.putIfAbsent(key, provider);
// 重复注册同一个 key 抛出异常
if (previous != null) {
throw new IllegalArgumentException("SavedStateProvider with the given key is"
+ " already registered");
}
}
@MainThread
// 解注册
public void unregisterSavedStateProvider(@NonNull String key) {
mComponents.remove(key);
}
public interface SavedStateProvider {
// 在组件被杀死之前调用用于返回要在页面重建后恢复的数据
Bundle saveState();
}
}
SavedStateRegistry 维护了一个 map 对象 key 是一个字符串 value 是一个 SavedStateProvider 接口只有一个方法,需要在组件被杀死时保存数据的地方实现此方法在组件被杀死前调用,在 performSave 时保存
// androidx.savedstate.SavedStateRegistry#performSave
void performSave(@NonNull Bundle outBundle) {
Bundle components = new Bundle();
// 如果还有上次重建时保存并且没有取出的数据再次保存
if (mRestoredState != null) {
components.putAll(mRestoredState);
}
// 遍历要保存数据的来源 map 调用其 saveState 方法保存
for (Iterator<Map.Entry<String, SavedStateProvider>> it =
mComponents.iteratorWithAdditions(); it.hasNext(); ) {
Map.Entry<String, SavedStateProvider> entry1 = it.next();
components.putBundle(entry1.getKey(), entry1.getValue().saveState());
}
// 保存到 outBundle 中
// outBundle 是 androidx.activity.ComponentActivity#onSaveInstanceState 方法传过来的
outBundle.putBundle(SAVED_COMPONENTS_KEY, components);
}
@MainThread
void performRestore(@NonNull Lifecycle lifecycle, @Nullable Bundle savedState) {
// 重复调用就抛出异常
if (mRestored) {
throw new IllegalStateException("SavedStateRegistry was already restored.");
}
// savedState 是 androidx.activity.ComponentActivity#onCreate 中传过来的
if (savedState != null) {
// 取出 performSave 中保存的数据
mRestoredState = savedState.getBundle(SAVED_COMPONENTS_KEY);
}
// 代码省略 ..
// 标记已恢复
mRestored = true;
}
Savedstate 源码比较少也比较简单就是对 onSaveInstanceState-onCreate 的包装扩展给开发者多一种选择来处理应用被杀死需要保存数据的场景
SavedStateHandle
ViewModel 只能处理系统配置更改引起的页面重建,当系统资源限制应用被杀死时 ViewModel 也被杀死了 SavedStateHandle 的引入使得开发者可以通过 ViewModel 来处理系统资源限制保存恢复数据相当于是对 ViewModel 功能的扩展。之前分析 ViewModel 的时候已经看到了
androidx.activity.ComponentActivity 实现了 HasDefaultViewModelProviderFactory 接口重写了 getDefaultViewModelProviderFactory 方法返回了 SavedStateViewModelFactory 对象并且在 create 中创建 ViewModel 对象时判断构造方法中是否有 SavedStateHandle 参数
// androidx.lifecycle.SavedStateViewModelFactory#create(java.lang.String, java.lang.Class<T>)
public <T extends ViewModel> T create(@NonNull String key, @NonNull Class<T> modelClass) {
boolean isAndroidViewModel = AndroidViewModel.class.isAssignableFrom(modelClass);
Constructor<T> constructor;
if (isAndroidViewModel && mApplication != null) {
constructor = findMatchingConstructor(modelClass, ANDROID_VIEWMODEL_SIGNATURE);
} else {
constructor = findMatchingConstructor(modelClass, VIEWMODEL_SIGNATURE);
}
if (constructor == null) {
// 如果构造方法里没有 ViewModel 参数到这里就返回了
return mFactory.create(modelClass);
}
// 静态方法创建 SavedStateHandleController 对象
SavedStateHandleController controller = SavedStateHandleController.create(
mSavedStateRegistry, mLifecycle, key, mDefaultArgs);
try {
T viewmodel;
// 如果是 AndroidViewModel 子类
if (isAndroidViewModel && mApplication != null) {
// 构造方法中传入 SavedStateHandle
viewmodel = constructor.newInstance(mApplication, controller.getHandle());
} else {
// 构造方法中传入 SavedStateHandle
viewmodel = constructor.newInstance(controller.getHandle());
}
viewmodel.setTagIfAbsent(TAG_SAVED_STATE_HANDLE_CONTROLLER, controller);
return viewmodel;
} catch (IllegalAccessException e) {
throw new RuntimeException("Failed to access " + modelClass, e);
} catch (InstantiationException e) {
throw new RuntimeException("A " + modelClass + " cannot be instantiated.", e);
} catch (InvocationTargetException e) {
throw new RuntimeException("An exception happened in constructor of "
+ modelClass, e.getCause());
}
}
// androidx.lifecycle.SavedStateHandleController#create
static SavedStateHandleController create(SavedStateRegistry registry, Lifecycle lifecycle,
String key, Bundle defaultArgs) {
// 根据 key 恢复数据
Bundle restoredState = registry.consumeRestoredStateForKey(key);
// 使用恢复的数据创建 SavedStateHandle 对象
SavedStateHandle handle = SavedStateHandle.createHandle(restoredState, defaultArgs);
SavedStateHandleController controller = new SavedStateHandleController(key, handle);
// 关联生命周期注册要保存的数据源
controller.attachToLifecycle(registry, lifecycle);
tryToAddRecreator(registry, lifecycle);
return controller;
}
在创建有以 SavedStateHandle 为构造参数的 ViewModel 时会使用恢复的数据创建
SavedStateHandle 对象作为参数用于创建 ViewModel 对象
// androidx.lifecycle.SavedStateHandleController#attachToLifecycle
void attachToLifecycle(SavedStateRegistry registry, Lifecycle lifecycle) {
if (mIsAttached) {
throw new IllegalStateException("Already attached to lifecycleOwner");
}
mIsAttached = true;
lifecycle.addObserver(this);
// 注册要保存的数据源,第二个参数是 SavedStateHandle 中的 SavedStateProvider
registry.registerSavedStateProvider(mKey, mHandle.savedStateProvider());
}
当应用被杀死时会调用所有 SavedStateProvider 的 saveState 方法
public final class SavedStateHandle {
// 最终要保存的数据
final Map<String, Object> mRegular;
// SavedStateHandle 也支持直接设置 SavedStateProvider 会存到这个 map 里
final Map<String, SavedStateProvider> mSavedStateProviders = new HashMap<>();
// 可以通过 key 返回一个 LiveData 对象在创建对象后会保存到这里下次不用重复创建
private final Map<String, SavingStateLiveData<?>> mLiveDatas = new HashMap<>();
private static final String VALUES = "values";
private static final String KEYS = "keys";
private final SavedStateProvider mSavedStateProvider = new SavedStateProvider() {
@SuppressWarnings("unchecked")
@NonNull
@Override
public Bundle saveState() {
// 遍历设置的 SavedStateProvider 调用其 saveState 方法返回一个 Bundle
// 保存到 mRegular 中
Map<String, SavedStateProvider> map = new HashMap<>(mSavedStateProviders);
for (Map.Entry<String, SavedStateProvider> entry : map.entrySet()) {
Bundle savedState = entry.getValue().saveState();
set(entry.getKey(), savedState);
}
// 遍历 mRegular 把 key-value 分别保存到两个列表中
Set<String> keySet = mRegular.keySet();
ArrayList keys = new ArrayList(keySet.size());
ArrayList value = new ArrayList(keys.size());
for (String key : keySet) {
keys.add(key);
value.add(mRegular.get(key));
}
Bundle res = new Bundle();
// 把两个列表存储到 Bundle 中返回出去存储到
// androidx.activity.ComponentActivity#onSaveInstanceState 方法的 Bundle
// Bundle 存 Bundle 一层套一层
res.putParcelableArrayList("keys", keys);
res.putParcelableArrayList("values", value);
return res;
}
};
public SavedStateHandle(@NonNull Map<String, Object> initialState) {
mRegular = new HashMap<>(initialState);
}
public SavedStateHandle() {
mRegular = new HashMap<>();
}
// 上面已经分析过 androidx.activity.ComponentActivity 默认返回的 ViewModelFactory 是
// androidx.lifecycle.SavedStateViewModelFactory 在 create 里会创建 SavedStateHandleController 对象
// 在 SavedStateHandleController 的 create 方法里会调用此方法创建 SavedStateHandle 对象
static SavedStateHandle createHandle(@Nullable Bundle restoredState,
@Nullable Bundle defaultState) {
// restoredState 是通过 androidx.savedstate.SavedStateRegistry#consumeRestoredStateForKey 返回的 Bundle
// 如果 restoredState 为 null 说明是正常打开页面或者页面销毁时并没有保存此 key
if (restoredState == null && defaultState == null) {
return new SavedStateHandle();
}
Map<String, Object> state = new HashMap<>();
// 默认值在 androidx.activity.ComponentActivity#getDefaultViewModelProviderFactory
// 方法里会尝试从 getIntent 方法中取
if (defaultState != null) {
for (String key : defaultState.keySet()) {
state.put(key, defaultState.get(key));
}
}
if (restoredState == null) {
// 如果 restoredState 就使用默认值创建一个 SavedStateHandle 对象返回
return new SavedStateHandle(state);
}
// 取出上面分析保存的 key-value
ArrayList keys = restoredState.getParcelableArrayList(KEYS);
ArrayList values = restoredState.getParcelableArrayList(VALUES);
if (keys == null || values == null || keys.size() != values.size()) {
throw new IllegalStateException("Invalid bundle passed as restored state");
}
for (int i = 0; i < keys.size(); i++) {
state.put((String) keys.get(i), values.get(i));
}
// 返回 SavedStateHandle 对象
return new SavedStateHandle(state);
}
@NonNull
SavedStateProvider savedStateProvider() {
return mSavedStateProvider;
}
}
SavedStateHandle 中有一个 SavedStateProvider 对象 mSavedStateProvider 并且也支持额外设置 SavedStateProvider 在页面被销毁调用 mSavedStateProvider 的 saveState 方法时遍历所有设置的 SavedStateProvider 调用 saveState 保存数据,并且每一层返回的都是 Bundle 对象,在创建 ViewModel 对象时会创建 SavedStateHandle 对象并且尝试恢复之前保存的数据,这样就可以通过 ViewModel 对象拿到之前保存的数据了
总结
SavedState 是对 onSaveInstanceState-onRestoreInstanceState 机制的封装可以处理因为系统资源限制应用被杀死时保存简单数据在页面重建时恢复
因为 ViewModel 只能处理系统配置更改引起的页面重建上述情况并不能处理 SavedStateHandle 是利用 SavedState 对 ViewModel 的扩展让开发者可以通过 ViewModel 处理上述场景,当 ViewModel 的构造方法中有 SavedStateHandle 参数时系统默认就会尝试恢复上次应用被杀死时保存的数据
参考与感谢
从源码看 Jetpack(7)- SavedStateHandle 源码详解
【背上Jetpack】绝不丢失的状态 androidx SaveState ViewModel-SaveState 分析
【安卓开发系列 – APP】JetPack – SavedState