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 参数设置为 trueActivity#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. 获取 nonConfigViewModel
  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 列表的。在 FragmentStoreFragmentManagerState 中都有这两个列表。

遍历 ActiveFragment 时会做以下操作,从上面的获取到的 FramgentSavedState 数据中去获取 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;
    }
}

最后将对应的 FragmentStateManagerFragmentStore 中标记为 Active 和设置 FragmentManager 的状态到 FragmentStateManager 中。

5.遍历 ViewModel 中的 RetainedFragment,如果其中有 Fragment 不在上面的恢复 Fragment 列表中,将他们移除

6.恢复 BackStackPrimaryNavigationFramgent 等等

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 的状态保存与恢复相关的问题可以从容地应对。

相关推荐
alexhilton2 天前
runBlocking实践:哪里该使用,哪里不该用
android·kotlin·android jetpack
Tans54 天前
Androidx Lifecycle 源码阅读笔记
android·android jetpack·源码阅读
凡小烦4 天前
LeakCanary源码解析
源码阅读·leakcanary
ljt27249606615 天前
Compose笔记(四十九)--SwipeToDismiss
android·笔记·android jetpack
4z337 天前
Jetpack Compose重组优化:机制剖析与性能提升策略
性能优化·android jetpack
alexhilton8 天前
Android ViewModel数据加载:基于Flow架构的最佳实践
android·kotlin·android jetpack
水牛11 天前
一行代码完成startActivityForResult
android·android jetpack
kymjs张涛11 天前
零一开源|前沿技术周刊 #14
android·android studio·android jetpack
alexhilton12 天前
Android应用的架构演进
android·kotlin·android jetpack