SavedStateViewModel(ViewModel + onSaveInstanceState)
ViewModel 可以在配置更改时保存状态;onSaveInstanceState 可以在内存不足进程被杀死时保存状态,onCreate 方法的 Bundle 参数可能为空,如果在 onCreate 方法里恢复数据,一定要做非空判断
onSaveInstanceState 调用时机
- 启动新的 Activity,导致原 Activity 被盖住时
- 默认情况下横竖屏切换时
- 手机息屏时
- 当用户按下手机 home 键时
- 长按手机home键或者按下菜单键时
各种 Android 系统操作都会影响 Fragment 的状态,为了确保用户的状态得到保存,Android 框架会自动保存和恢复 Fragment 和返回堆栈
// FragmentActivity
final FragmentController mFragments =
FragmentController.createController(new HostCallbacks());
addOnContextAvailableListener(new OnContextAvailableListener() {
@Override
public void onContextAvailable(@NonNull Context context) {
mFragments.attachHost(null /*parent*/);
Bundle savedInstanceState = getSavedStateRegistry()
.consumeRestoredStateForKey(FRAGMENTS_TAG);
if (savedInstanceState != null) {
Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);
mFragments.restoreSaveState(p);
}
}
});
// FragmentController
public void restoreSaveState(@Nullable Parcelable state) {
mHost.mFragmentManager.restoreSaveState(state);
}
// FragmentManager
fragmentStateManager = new FragmentStateManager(mLifecycleCallbacksDispatcher,
mFragmentStore, mHost.getContext().getClassLoader(),
getFragmentFactory(), fs);
// FragmentStateManager
FragmentStateManager(FragmentLifecycleCallbacksDispatcher dispatcher,
FragmentStore fragmentStore, ClassLoader classLoader,
FragmentFactory fragmentFactory, FragmentState fs) {
mDispatcher = dispatcher;
mFragmentStore = fragmentStore;
mFragment = fragmentFactory.instantiate(classLoader, fs.mClassName);
if (fs.mArguments != null) {
fs.mArguments.setClassLoader(classLoader);
}
mFragment.setArguments(fs.mArguments);
if (fs.mSavedFragmentState != null) {
mFragment.mSavedFragmentState = fs.mSavedFragmentState;
} else {
mFragment.mSavedFragmentState = new Bundle();
}
}
// 在 Fragment 中恢复自定义的 SavedState
void activityCreated() {
if (FragmentManager.isLoggingEnabled(Log.DEBUG)) {
Log.d(TAG, "moveto ACTIVITY_CREATED: " + mFragment);
}
mFragment.performActivityCreated(mFragment.mSavedFragmentState);
mDispatcher.dispatchOnFragmentActivityCreated(
mFragment, mFragment.mSavedFragmentState, false);
}
Android 框架提供的所有视图都有自己的 onSaveInstanceState 和 onRestoreInstanceState 实现,因此您不必管理 Fragment 中的视图状态。视图需要一个 ID 才能保留其状态,此 ID 在 Fragment 及其视图层次结构中必须是唯一的,没有 ID 的视图无法保留其状态
onSaveInstanceState 数据存储位置和大小限制
onSaveInstanceState 中保存的 Bundle 数据最终会通过 IActivityManager 保存在系统内存中,由于需要通过 Binder 进行通讯,而 Binder 传输缓冲区有 1M 大小的限制,所以 onSaveInstanceState 也有相同的限制
ViewModel 原理
- 不会因配置改变而销毁
- 用于管理 UI 界面数据,将加载数据与数据恢复从 Activity / Fragment中解耦
- 多个 Fragment 可以共享同一 ViewModel
- 配合 LiveData,可感知生命周期
通过 Fragment.setRetainedFragment 或 Activity.onSaveNonConfigurationInstance 保存的数据都可以在配置改变时不销毁
关键类:ViewModelProvider(辅助工具类)、 ViewModelStore(通过 Key 保存了不同的 ViewModel)
在宿主 Activity 创建时,默认会在其 FramgentManager 中创建一个 FragmentManagerViewModel。同时将生成的 FragmentManagerViewModel 存储在其本身的 ViewModelStore 中,同时使用自身的 FragmentManager 的名称作为 Key 值
子 Fragment 通过 getFragmentManager 持有父 FragmentManager,自身的 ViewModelStore 保存自己的 ViewModel,并存入父 FragmentManagerViewModel 的 mViewModelStores 中,自身的 FragmentManagerViewModel 存入父 FragmentManagerViewModel 的 mChildNonConfigs中