Androidx Fragment 源码阅读笔记(上)

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() 方法中会监控很多的信息,我这里简单列举一下:

  1. 监控 Fragment 的添加,然后回调给父 Fragment(如果有的话)
  2. 监控返回按键
  3. 获取 nonConfig 的 ViewModel
  4. 监控 onSaveInstanceState() 方法回调,回调时保存所有的 Fragment 状态,恢复上次保存的 Fragment 状态,分别调用的方法是 saveAllStateInternal() 和 restoreSaveStateInternal()
  5. 监控 Activity Result 回调
  6. 监控 Activity 权限回调
  7. 监控 Activity 配置改变
  8. 监控低内存
  9. 监控多窗口模式
  10. 监控画中画模式
  11. 监控 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);
}

上面逻辑稍微有点复杂,理一下。

  1. 恢复所有 Fragment 中的 Result 信息
  2. 恢复所有 Fragment 中的 SavedState 信息,并保存到 FragmentStore 中,供后续操作使用
  3. 恢复 FragmentManagerState
  4. 遍历所有的 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 的状态保存与恢复相关的问题可以从容地应对。

相关推荐
alexhilton4 天前
藏在设备上的秘密,终究藏不住
android·kotlin·android jetpack
Amos_Web4 天前
Rspack 源码解析(十一):资产 Hook 与增量构建
前端·rust·源码阅读
传奇开心果编程5 天前
【Jetpack Compose基础语法学与练】第8课 rememberSaveable,页面旋转/系统重建保留状态
android·学习·ui·kotlin·android jetpack
传奇开心果编程5 天前
【Jetpack Compose基础语法学与练】第7课 if条件渲染 + 列表基础(LazyColumn)
学习·ui·kotlin·android jetpack
Amos_Web5 天前
Rspack 源码解析(十):Hash 与 Asset 生成
前端·rust·源码阅读
传奇开心果编程5 天前
【Jetpack Compose基础语法学与练】第9课 SideEffect副作用 + LaunchedEffect,处理异步任务和生命周期
android·学习·ui·kotlin·android jetpack
惟恋惜6 天前
第 3 章 · 列表、滚动与 Lazy 深入:告别 RecyclerView 思维
ui·android jetpack
程序猿阿越6 天前
containerd如何创建Pod
后端·kubernetes·源码阅读
传奇开心果编程7 天前
【Jetpack Compose基础语法学与练】第6课 TextField文本输入,字符串状态与输入交互
学习·前端框架·kotlin·android jetpack
Amos_Web7 天前
Rspack 源码解析(八):Module、Chunk 与 Runtime ID
前端·rust·源码阅读