Fragment
应该没有人不知道,到今天才稍微有点仔细的读它的源码,稍微有点不应该,在使用 Fragment
的时候,经验较少的同学或多或少都遇到一些问题,甚至一些崩溃。今天我们来一起读一下他的源码,从源码的角度来看看那些年我们遇到过的 Bug 该怎么解决。
我们的切入点是 FragmentActivity
, 他的继承关系是 androidx.fragment.app.FragmentActivity
-> androidx.activity.ComponentActivity
-> androidx.core.app.ComponentActivity
-> Activity
。
先来看看 FragmentActivity
的初始化方法:
Kotlin
public FragmentActivity() {
super();
init();
}
private void init() {
getSavedStateRegistry().registerSavedStateProvider(LIFECYCLE_TAG, () -> { // Activity#onSaveInstanceState() 方法回调
// 将 FragmentManager 的状态设置为 CREATED
markFragmentsCreated();
// 再将 FragmentManager 的状态设置为 STOPPED
mFragmentLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_STOP);
return new Bundle();
});
// Ensure that the first OnConfigurationChangedListener
// marks the FragmentManager's state as not saved
addOnConfigurationChangedListener(newConfig ->
// 配置改变,将 FragmentManager 的 mStateSaved 设置为 false
mFragments.noteStateNotSaved()
);
// Ensure that the first OnNewIntentListener
// marks the FragmentManager's state as not saved
addOnNewIntentListener(newConfig ->
// onNewIntent() 回调,将 FragmentManager 的 mStateSaved 设置为 false
mFragments.noteStateNotSaved()
);
addOnContextAvailableListener(context ->
// onCreate() 回调,将 FragmentManager 的 mStateSaved 设置为 false
mFragments.attachHost(null /*parent*/)
);
}
要较为深入地理解 Fragment
,理解 Activity#onSaveInstanceState()
和 Activity#onRetainNonConfigurationInstance()
较为重要,我以前写过相关的文章,不清楚的同学可以先学习一下:[Framework] 关于 Activity#onSaveInstanceState() 的笔记 和 [Framework] ViewModel 如何做到 Activity 重启不丢失数据。我这里就不多说了,默认认为大家都理解了他们。
当 Activity#onSaveInstanceState()
执行后会将所有的 Fragment
信息保存,供需要时恢复上次的状态时使用(后面会看到这部份代码),保存完毕后会将 FragmentManager#mStateSaved
参数设置为 true
。Activity#onSaveInstanceState()
方法是在 Activity#onStop()
生命周期调用后才调用,所以在 Activity#onStop()
生命周期前都会将 FragmentManager#mStateSaved
手动设置为 false
。比如上面的初始化代码中就有挺多,不仅仅是这些生命周期哈,还有很多别的,我就不多说了。
所以这里就有第一个知识点,当 FragmentManager
已经执行完毕数据保存后,你再去调用事务提交方法 commit()
方法就会出现以下崩溃信息:
text
Can not perform this action after onSaveInstanceState
因为已经执行完毕数据状态的保存了,这时你再提交新的 Fragment
,那么你的新的 Fragment
的数据就无法保存,会丢失,所以就会报错。
如果你不希望由于状态丢失而导致崩溃,那么就需要调用 commitAllowingStateLoss()
方法去提交事务。
上面的废话说得有点多了,我们继续追踪源码。从初始化的代码中可以看出,当 onCreate()
回调后,会调用 FragmentController#attachHost()
方法:
Java
public void attachHost(@Nullable Fragment parent) {
mHost.mFragmentManager.attachController(
mHost, mHost /*container*/, parent);
}
@SuppressWarnings("deprecation")
@SuppressLint("SyntheticAccessor")
void attachController(@NonNull FragmentHostCallback<?> host,
@NonNull FragmentContainer container, @Nullable final Fragment parent) {
if (mHost != null) throw new IllegalStateException("Already attached");
mHost = host;
mContainer = container;
mParent = parent;
// Add a FragmentOnAttachListener to the parent fragment / host to support
// backward compatibility with the deprecated onAttachFragment() APIs
if (mParent != null) { // Activity 时 mParent 为空
// 监控当前 FragmentManager 中的 Fragment attach,然后回调给父 Fragemnt 去
addFragmentOnAttachListener(new FragmentOnAttachListener() {
@SuppressWarnings("deprecation")
@Override
public void onAttachFragment(@NonNull FragmentManager fragmentManager,
@NonNull Fragment fragment) {
parent.onAttachFragment(fragment);
}
});
} else if (host instanceof FragmentOnAttachListener) {
addFragmentOnAttachListener((FragmentOnAttachListener) host);
}
if (mParent != null) {
// Since the callback depends on us being the primary navigation fragment,
// update our callback now that we have a parent so that we have the correct
// state by default
updateOnBackPressedCallbackEnabled();
}
// Set up the OnBackPressedCallback
if (host instanceof OnBackPressedDispatcherOwner) { // 监听 BackPress.
OnBackPressedDispatcherOwner dispatcherOwner = ((OnBackPressedDispatcherOwner) host);
mOnBackPressedDispatcher = dispatcherOwner.getOnBackPressedDispatcher();
LifecycleOwner owner = parent != null ? parent : dispatcherOwner;
mOnBackPressedDispatcher.addCallback(owner, mOnBackPressedCallback);
}
// Get the FragmentManagerViewModel
// 获取 mNonConfig,他就是一个 ViewModel
if (parent != null) {
mNonConfig = parent.mFragmentManager.getChildNonConfig(parent);
} else if (host instanceof ViewModelStoreOwner) {
ViewModelStore viewModelStore = ((ViewModelStoreOwner) host).getViewModelStore();
mNonConfig = FragmentManagerViewModel.getInstance(viewModelStore);
} else {
mNonConfig = new FragmentManagerViewModel(false);
}
// Ensure that the state is in sync with FragmentManager
// 标记是否已经执行 StateSaved.
mNonConfig.setIsStateSaved(isStateSaved());
mFragmentStore.setNonConfig(mNonConfig);
if (mHost instanceof SavedStateRegistryOwner && parent == null) {
// 监听 onSaveInstanceState() 回调
SavedStateRegistry registry =
((SavedStateRegistryOwner) mHost).getSavedStateRegistry();
registry.registerSavedStateProvider(SAVED_STATE_KEY, () -> {
// 回调 onSaveInstanceState() 执行数据保存
return saveAllStateInternal();
}
);
// 获取上次保存的数据
Bundle savedInstanceState = registry
.consumeRestoredStateForKey(SAVED_STATE_KEY);
if (savedInstanceState != null) {
// 恢复数据
restoreSaveStateInternal(savedInstanceState);
}
}
if (mHost instanceof ActivityResultRegistryOwner) { // 监控 Activity Result 信息
ActivityResultRegistry registry =
((ActivityResultRegistryOwner) mHost).getActivityResultRegistry();
String parentId = parent != null ? parent.mWho + ":" : "";
String keyPrefix = "FragmentManager:" + parentId;
mStartActivityForResult = registry.register(keyPrefix + "StartActivityForResult",
new ActivityResultContracts.StartActivityForResult(),
new ActivityResultCallback<ActivityResult>() {
@Override
public void onActivityResult(ActivityResult result) {
LaunchedFragmentInfo requestInfo = mLaunchedFragments.pollLast();
if (requestInfo == null) {
Log.w(TAG, "No Activities were started for result for " + this);
return;
}
String fragmentWho = requestInfo.mWho;
int requestCode = requestInfo.mRequestCode;
Fragment fragment = mFragmentStore.findFragmentByWho(fragmentWho);
// Although unlikely, it is possible this fragment could be null if a
// fragment transactions was committed immediately after the for
// result call
if (fragment == null) {
Log.w(TAG,
"Activity result delivered for unknown Fragment "
+ fragmentWho);
return;
}
fragment.onActivityResult(requestCode, result.getResultCode(),
result.getData());
}
});
mStartIntentSenderForResult = registry.register(keyPrefix
+ "StartIntentSenderForResult",
new FragmentManager.FragmentIntentSenderContract(),
new ActivityResultCallback<ActivityResult>() {
@Override
public void onActivityResult(ActivityResult result) {
LaunchedFragmentInfo requestInfo = mLaunchedFragments.pollFirst();
if (requestInfo == null) {
Log.w(TAG, "No IntentSenders were started for " + this);
return;
}
String fragmentWho = requestInfo.mWho;
int requestCode = requestInfo.mRequestCode;
Fragment fragment = mFragmentStore.findFragmentByWho(fragmentWho);
// Although unlikely, it is possible this fragment could be null if a
// fragment transactions was committed immediately after the for
// result call
if (fragment == null) {
Log.w(TAG, "Intent Sender result delivered for unknown Fragment "
+ fragmentWho);
return;
}
fragment.onActivityResult(requestCode, result.getResultCode(),
result.getData());
}
});
// 权限回调监控
mRequestPermissions = registry.register(keyPrefix + "RequestPermissions",
new ActivityResultContracts.RequestMultiplePermissions(),
new ActivityResultCallback<Map<String, Boolean>>() {
@SuppressLint("SyntheticAccessor")
@Override
public void onActivityResult(Map<String, Boolean> result) {
String[] permissions = result.keySet().toArray(new String[0]);
ArrayList<Boolean> resultValues = new ArrayList<>(result.values());
int[] grantResults = new int[resultValues.size()];
for (int i = 0; i < resultValues.size(); i++) {
grantResults[i] = resultValues.get(i)
? PackageManager.PERMISSION_GRANTED
: PackageManager.PERMISSION_DENIED;
}
LaunchedFragmentInfo requestInfo = mLaunchedFragments.pollFirst();
if (requestInfo == null) {
Log.w(TAG, "No permissions were requested for " + this);
return;
}
String fragmentWho = requestInfo.mWho;
int requestCode = requestInfo.mRequestCode;
Fragment fragment = mFragmentStore.findFragmentByWho(fragmentWho);
// Although unlikely, it is possible this fragment could be null if a
// fragment transactions was committed immediately after the request
// permissions call
if (fragment == null) {
Log.w(TAG, "Permission request result delivered for unknown "
+ "Fragment " + fragmentWho);
return;
}
fragment.onRequestPermissionsResult(requestCode, permissions,
grantResults);
}
});
}
if (mHost instanceof OnConfigurationChangedProvider) { // Configure 改变监控
OnConfigurationChangedProvider onConfigurationChangedProvider =
(OnConfigurationChangedProvider) mHost;
onConfigurationChangedProvider.addOnConfigurationChangedListener(
mOnConfigurationChangedListener);
}
if (mHost instanceof OnTrimMemoryProvider) { // 低内存监控
OnTrimMemoryProvider onTrimMemoryProvider = (OnTrimMemoryProvider) mHost;
onTrimMemoryProvider.addOnTrimMemoryListener(mOnTrimMemoryListener);
}
if (mHost instanceof OnMultiWindowModeChangedProvider) { // 多屏幕监控
OnMultiWindowModeChangedProvider onMultiWindowModeChangedProvider =
(OnMultiWindowModeChangedProvider) mHost;
onMultiWindowModeChangedProvider.addOnMultiWindowModeChangedListener(
mOnMultiWindowModeChangedListener);
}
if (mHost instanceof OnPictureInPictureModeChangedProvider) { // 画中画模式监控
OnPictureInPictureModeChangedProvider onPictureInPictureModeChangedProvider =
(OnPictureInPictureModeChangedProvider) mHost;
onPictureInPictureModeChangedProvider.addOnPictureInPictureModeChangedListener(
mOnPictureInPictureModeChangedListener);
}
if (mHost instanceof MenuHost && parent == null) { // Menu 监控
((MenuHost) mHost).addMenuProvider(mMenuProvider);
}
}
FragmentManager#attachHost()
方法中会监控很多的信息,我这里简单列举一下:
- 监控
Fragment
的添加,然后回调给父Fragment
(如果有的话) - 监控返回按键
- 获取
nonConfig
的ViewModel
- 监控
onSaveInstanceState()
方法回调,回调时保存所有的Fragment
状态,恢复上次保存的Fragment
状态,分别调用的方法是saveAllStateInternal()
和restoreSaveStateInternal()
- 监控
Activity Result
回调 - 监控
Activity
权限回调 - 监控
Activity
配置改变 - 监控低内存
- 监控多窗口模式
- 监控画中画模式
- 监控
Menu
我个人最关心的逻辑是状态的保存与恢复,其他的逻辑大家如果感兴趣就只有自己去看看罗,本篇文章只会看状态的保存与恢复。
这里先说个题外话,相信很多人和我一样,很多人也非常讨厌这个状态的保存与恢复,而且这东西还容易造成崩溃,我之前就发现一些线上的用户在恢复数据的时候崩溃,崩溃的异常大致是恢复数据的过程中加载某个 Class
失败,到目前为止我都不知道为啥会有这个异常。
Fragment
并没有提供某个方法可以关闭状态的保存与恢复功能,但是我们可以提供一个操作将保存到 Bundle
中的 Fragment
相关数据将其移除掉。
Kotlin
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
val components = outState.getBundle("androidx.lifecycle.BundlableSavedStateRegistry.key")
if (components != null && components.containsKey("android:support:fragments")) {
components.remove("android:support:fragments")
tUiUtilsLog.w(TAG, "Remove fragment's states: onSaveInstanceState()")
}
}
Fragment 数据恢复
废话说得有点多了,我们言归正传,看看 restoreSaveStateInternal()
方法是如何恢复状态数据的。
Java
void restoreSaveStateInternal(@Nullable Parcelable state) {
// If there is no saved state at all, then there's nothing else to do
if (state == null) return;
Bundle bundle = (Bundle) state;
// Restore the fragment results
// 恢复 result 数据
for (String bundleKey : bundle.keySet()) {
if (bundleKey.startsWith(RESULT_KEY_PREFIX)) {
Bundle savedResult = bundle.getBundle(bundleKey);
if (savedResult != null) {
savedResult.setClassLoader(mHost.getContext().getClassLoader());
String resultKey = bundleKey.substring(RESULT_KEY_PREFIX.length());
mResults.put(resultKey, savedResult);
}
}
}
// Restore the saved bundle for all fragments
// 恢复 Fragment State 数据
HashMap<String, Bundle> allStateBundles = new HashMap<>();
for (String bundleKey : bundle.keySet()) {
if (bundleKey.startsWith(FRAGMENT_KEY_PREFIX)) {
Bundle savedFragmentBundle = bundle.getBundle(bundleKey);
if (savedFragmentBundle != null) {
savedFragmentBundle.setClassLoader(mHost.getContext().getClassLoader());
String fragmentKey = bundleKey.substring(FRAGMENT_KEY_PREFIX.length());
allStateBundles.put(fragmentKey, savedFragmentBundle);
}
}
}
// 将恢复的 Fragment State 数据交给 FragmentStore 处理
mFragmentStore.restoreSaveState(allStateBundles);
// 恢复 FragmentManagerState
FragmentManagerState fms = bundle.getParcelable(FRAGMENT_MANAGER_STATE_KEY);
if (fms == null) return;
// Build the full list of active fragments, instantiating them from
// their saved state.
// 清除之前的 Active 的 Fragment 列表
mFragmentStore.resetActiveFragments();
// 遍历 FragmentManagerState 中的 Active 状态的 Fragment.
for (String who : fms.mActive) {
// Retrieve any saved state, clearing it out for future calls
// 获取并将原来的 Fragment 数据设置为空
Bundle stateBundle = mFragmentStore.setSavedState(who, null);
if (stateBundle != null) {
FragmentStateManager fragmentStateManager;
// 获取 FragmentState
FragmentState fs = stateBundle.getParcelable(
FragmentStateManager.FRAGMENT_STATE_KEY);
// 获取 ViewModel 中的 Fragment 示例
Fragment retainedFragment = mNonConfig.findRetainedFragmentByWho(fs.mWho);
if (retainedFragment != null) {
// 直接使用 ViewModel 中的 Fragment
if (isLoggingEnabled(Log.VERBOSE)) {
Log.v(TAG, "restoreSaveState: re-attaching retained "
+ retainedFragment);
}
fragmentStateManager = new FragmentStateManager(mLifecycleCallbacksDispatcher,
mFragmentStore, retainedFragment, stateBundle);
} else {
// ViewModel 中没有保存 Fragment,需要创建一个新的 Fragment 实例
fragmentStateManager = new FragmentStateManager(mLifecycleCallbacksDispatcher,
mFragmentStore, mHost.getContext().getClassLoader(),
getFragmentFactory(), stateBundle);
}
Fragment f = fragmentStateManager.getFragment();
// 将保存的 State 数据设置给 Fragment
f.mSavedFragmentState = stateBundle;
// 设置 FragmentManager
f.mFragmentManager = this;
if (isLoggingEnabled(Log.VERBOSE)) {
Log.v(TAG, "restoreSaveState: active (" + f.mWho + "): " + f);
}
// 根据 Fragment#mSavedFragmentState中的数据再恢复其他的数据
fragmentStateManager.restoreState(mHost.getContext().getClassLoader());
// 将当前的 Fragment 标记为 Active
mFragmentStore.makeActive(fragmentStateManager);
// Catch the FragmentStateManager up to our current state
// In almost all cases, this is Fragment.INITIALIZING, but just in
// case a FragmentController does something...unique, let's do this anyways.
// 为 FragmentStateManager 设置 FragmentManager 的状态
fragmentStateManager.setFragmentManagerState(mCurState);
}
}
// Check to make sure there aren't any retained fragments that aren't in mActive
// This can happen if a retained fragment is added after the state is saved
// 检查 ViewModel 中的 Fragment,如果他们不在上面恢复的 Fragment 中,将其移出
for (Fragment f : mNonConfig.getRetainedFragments()) {
if (!mFragmentStore.containsActiveFragment(f.mWho)) {
// 移除 Fragment
if (isLoggingEnabled(Log.VERBOSE)) {
Log.v(TAG, "Discarding retained Fragment " + f
+ " that was not found in the set of active Fragments " + fms.mActive);
}
mNonConfig.removeRetainedFragment(f);
// We need to ensure that onDestroy and any other clean up is done
// so move the Fragment up to CREATED, then mark it as being removed, then
// destroy it without actually adding the Fragment to the FragmentStore
f.mFragmentManager = this;
FragmentStateManager fragmentStateManager = new FragmentStateManager(
mLifecycleCallbacksDispatcher, mFragmentStore, f);
// 如果被移除的 Fragment 还没有执行 onCreate 生命周期,先执行
fragmentStateManager.setFragmentManagerState(Fragment.CREATED);
fragmentStateManager.moveToExpectedState();
// 然后执行移除,最后回调 onDestory()
f.mRemoving = true;
fragmentStateManager.moveToExpectedState();
}
}
// Build the list of currently added fragments.
// 恢复 Add 的 Fragment
mFragmentStore.restoreAddedFragments(fms.mAdded);
// Build the back stack.
// 恢复没有执行完成的任务
if (fms.mBackStack != null) {
mBackStack = new ArrayList<>(fms.mBackStack.length);
for (int i = 0; i < fms.mBackStack.length; i++) {
BackStackRecord bse = fms.mBackStack[i].instantiate(this);
if (isLoggingEnabled(Log.VERBOSE)) {
Log.v(TAG, "restoreAllState: back stack #" + i
+ " (index " + bse.mIndex + "): " + bse);
LogWriter logw = new LogWriter(TAG);
PrintWriter pw = new PrintWriter(logw);
bse.dump(" ", pw, false);
pw.close();
}
mBackStack.add(bse);
}
} else {
mBackStack = null;
}
mBackStackIndex.set(fms.mBackStackIndex);
// 恢复 PrimaryNavigation 的 Fragment
if (fms.mPrimaryNavActiveWho != null) {
mPrimaryNav = findActiveFragment(fms.mPrimaryNavActiveWho);
dispatchParentPrimaryNavigationFragmentChanged(mPrimaryNav);
}
ArrayList<String> savedBackStackStateKeys = fms.mBackStackStateKeys;
if (savedBackStackStateKeys != null) {
for (int i = 0; i < savedBackStackStateKeys.size(); i++) {
mBackStackStates.put(savedBackStackStateKeys.get(i), fms.mBackStackStates.get(i));
}
}
mLaunchedFragments = new ArrayDeque<>(fms.mLaunchedFragments);
}
上面逻辑稍微有点复杂,理一下。
- 恢复所有
Fragment
中的Result
信息 - 恢复所有
Fragment
中的SavedState
信息,并保存到FragmentStore
中,供后续操作使用 - 恢复
FragmentManagerState
- 遍历所有的
FragmentManagerState
中的Active
列表中的Fragment
这里还要简单介绍一下Fragment
的状态:
Java
static final int INITIALIZING = -1; // Not yet attached.
static final int ATTACHED = 0; // Attached to the host.
static final int CREATED = 1; // Created.
static final int VIEW_CREATED = 2; // View Created.
static final int AWAITING_EXIT_EFFECTS = 3; // Downward state, awaiting exit effects
static final int ACTIVITY_CREATED = 4; // Fully created, not started.
static final int STARTED = 5; // Created and started, not resumed.
static final int AWAITING_ENTER_EFFECTS = 6; // Upward state, awaiting enter effects
static final int RESUMED = 7; // Created started and resumed.
它和 Lifecycle
中的生命周期状态类似,值越大,生命周期越旺盛。当执行完毕 ATTACHED
状态后,Fragment
就会被添加到 Active
列表中,执行完 CREATED
就会被添加到 Add
列表中。也就是说 Active
列表一定是大于等于 Add
列表的。在 FragmentStore
和 FragmentManagerState
中都有这两个列表。
遍历 Active
的 Fragment
时会做以下操作,从上面的获取到的 Framgent
的 SavedState
数据中去获取 FragmentState
数据。然后在去 ViewModel
中再去获取对应的 Fragment
,如果获取失败,就会再创建一个新的实例。
这里又有一个小知识点,当 Fragment
设置 mRetainInstance
后,Fragment
就会保存到 ViewModel
中,然后下次恢复的时候就尝试从 ViewModel
中获取,不需要再创建新的示例。对应的代码如下(不过该方法已经标记弃用了):
Java
@Deprecated
public void setRetainInstance(boolean retain) {
FragmentStrictMode.onSetRetainInstanceUsage(this);
mRetainInstance = retain;
if (mFragmentManager != null) {
if (retain) {
mFragmentManager.addRetainedFragment(this);
} else {
mFragmentManager.removeRetainedFragment(this);
}
} else {
mRetainInstanceChangedWhileDetached = true;
}
}
void addRetainedFragment(@NonNull Fragment f) {
mNonConfig.addRetainedFragment(f);
}
构建 Fragment
对应的 FragmentStateManager
,然后将 SavedState
保存到 Fragment
中,然后通过它再恢复一堆数据,代码如下:
Java
void restoreState(@NonNull ClassLoader classLoader) {
if (mFragment.mSavedFragmentState == null) {
return;
}
mFragment.mSavedFragmentState.setClassLoader(classLoader);
Bundle savedInstanceState = mFragment.mSavedFragmentState.getBundle(
SAVED_INSTANCE_STATE_KEY);
if (savedInstanceState == null) {
// When restoring a Fragment, always ensure we have a
// non-null Bundle so that developers have a signal for
// when the Fragment is being restored
mFragment.mSavedFragmentState.putBundle(SAVED_INSTANCE_STATE_KEY,
new Bundle());
}
mFragment.mSavedViewState = mFragment.mSavedFragmentState.getSparseParcelableArray(
VIEW_STATE_KEY);
mFragment.mSavedViewRegistryState = mFragment.mSavedFragmentState.getBundle(
VIEW_REGISTRY_STATE_KEY);
FragmentState fs =
mFragment.mSavedFragmentState.getParcelable(FRAGMENT_STATE_KEY);
if (fs != null) {
mFragment.mTargetWho = fs.mTargetWho;
mFragment.mTargetRequestCode = fs.mTargetRequestCode;
if (mFragment.mSavedUserVisibleHint != null) {
mFragment.mUserVisibleHint = mFragment.mSavedUserVisibleHint;
mFragment.mSavedUserVisibleHint = null;
} else {
mFragment.mUserVisibleHint = fs.mUserVisibleHint;
}
}
if (!mFragment.mUserVisibleHint) {
mFragment.mDeferStart = true;
}
}
最后将对应的 FragmentStateManager
在 FragmentStore
中标记为 Active
和设置 FragmentManager
的状态到 FragmentStateManager
中。
5.遍历 ViewModel
中的 RetainedFragment
,如果其中有 Fragment
不在上面的恢复 Fragment
列表中,将他们移除
6.恢复 BackStack
和 PrimaryNavigationFramgent
等等
Fragment 数据保存
直接看 saveAllStateInternal()
方法:
Java
@NonNull
Bundle saveAllStateInternal() {
Bundle bundle = new Bundle();
// Make sure all pending operations have now been executed to get
// our state update-to-date.
// 强制执行完所有没有完成的任务
forcePostponedTransactions();
endAnimatingAwayFragments();
execPendingActions(true);
// 标记已经执行了数据保存
mStateSaved = true;
mNonConfig.setIsStateSaved(true);
// First save all active fragments.
// 获取所有的 Active 的 Fragment
ArrayList<String> active = mFragmentStore.saveActiveFragments();
// And grab all fragments' saved state bundles
// 获取所有的 Fragment 已经保存的状态
HashMap<String, Bundle> savedState = mFragmentStore.getAllSavedState();
if (savedState.isEmpty()) {
if (isLoggingEnabled(Log.VERBOSE)) {
Log.v(TAG, "saveAllState: no fragments!");
}
} else {
// Build list of currently added fragments.
ArrayList<String> added = mFragmentStore.saveAddedFragments();
// Now save back stack.
// 收集 BackStack
BackStackRecordState[] backStack = null;
if (mBackStack != null) {
int size = mBackStack.size();
if (size > 0) {
backStack = new BackStackRecordState[size];
for (int i = 0; i < size; i++) {
backStack[i] = new BackStackRecordState(mBackStack.get(i));
if (isLoggingEnabled(Log.VERBOSE)) {
Log.v(TAG, "saveAllState: adding back stack #" + i
+ ": " + mBackStack.get(i));
}
}
}
}
// 构建新的 FragmentManagerState 示例用于保存
FragmentManagerState fms = new FragmentManagerState();
// 保存 Active Fragment
fms.mActive = active;
// 保存 Added Fragment
fms.mAdded = added;
// 保存 BackStack
fms.mBackStack = backStack;
fms.mBackStackIndex = mBackStackIndex.get();
// 保存 PrimaryNavigationFragment
if (mPrimaryNav != null) {
fms.mPrimaryNavActiveWho = mPrimaryNav.mWho;
}
fms.mBackStackStateKeys.addAll(mBackStackStates.keySet());
fms.mBackStackStates.addAll(mBackStackStates.values());
// 保存 LauncherFragment
fms.mLaunchedFragments = new ArrayList<>(mLaunchedFragments);
// 将 FragmentManagerState 写入 bundle
bundle.putParcelable(FRAGMENT_MANAGER_STATE_KEY, fms);
// 写入 Result 数据到 bundle
for (String resultName : mResults.keySet()) {
bundle.putBundle(RESULT_KEY_PREFIX + resultName, mResults.get(resultName));
}
// 写入所有的 Fragment 的状态
for (String fWho : savedState.keySet()) {
bundle.putBundle(FRAGMENT_KEY_PREFIX + fWho, savedState.get(fWho));
}
}
return bundle;
}
保存的代码要简单很多,保存前先执行完所有没有完成的任务,首先保存 FragmentManagerState
,然后保存所有的 FragmentState
。
最后
希望在本篇文章后,你对 Fragment
的状态保存与恢复相关的问题可以从容地应对。