美文网首页
Android-Fragment的状态保存和恢复

Android-Fragment的状态保存和恢复

作者: zzq_nene | 来源:发表于2020-12-12 18:49 被阅读0次

一、FragmentActivity#onSaveInstanceState

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        markFragmentsCreated();
        // 调用FragmentController的saveAllState保存状态,将状态数据保存在Parcelable对象中
        Parcelable p = mFragments.saveAllState();
        if (p != null) {
            outState.putParcelable(FRAGMENTS_TAG, p);
        }
        if (mPendingFragmentActivityResults.size() > 0) {
            outState.putInt(NEXT_CANDIDATE_REQUEST_INDEX_TAG, mNextCandidateRequestIndex);

            int[] requestCodes = new int[mPendingFragmentActivityResults.size()];
            String[] fragmentWhos = new String[mPendingFragmentActivityResults.size()];
            for (int i = 0; i < mPendingFragmentActivityResults.size(); i++) {
                requestCodes[i] = mPendingFragmentActivityResults.keyAt(i);
                fragmentWhos[i] = mPendingFragmentActivityResults.valueAt(i);
            }
            outState.putIntArray(ALLOCATED_REQUEST_INDICIES_TAG, requestCodes);
            outState.putStringArray(REQUEST_FRAGMENT_WHO_TAG, fragmentWhos);
        }
    }

1.onSaveInstanceState方法的调用触发流程

该方法的调用,是从ActivityThread触发的。比如在ActivityThread触发调用Activity的pause生命周期的时候,会调用performPauseActivity方法,在这里会执行下面代码:

(1)ActivityThread
        // 判断是否需要保存状态
        final boolean shouldSaveState = !r.activity.mFinished && r.isPreHoneycomb();
        if (shouldSaveState) {
            callActivityOnSaveInstanceState(r);
        }
    private void callActivityOnSaveInstanceState(ActivityClientRecord r) {
        r.state = new Bundle();
        r.state.setAllowFds(false);
        if (r.isPersistable()) {
            r.persistentState = new PersistableBundle();
            mInstrumentation.callActivityOnSaveInstanceState(r.activity, r.state,
                    r.persistentState);
        } else {
            mInstrumentation.callActivityOnSaveInstanceState(r.activity, r.state);
        }
    }
(2)Instrumentation
    public void callActivityOnSaveInstanceState(@NonNull Activity activity,
            @NonNull Bundle outState) {
        activity.performSaveInstanceState(outState);
    }


    public void callActivityOnSaveInstanceState(@NonNull Activity activity,
            @NonNull Bundle outState, @NonNull PersistableBundle outPersistentState) {
        activity.performSaveInstanceState(outState, outPersistentState);
    }
(3)Activity
    final void performSaveInstanceState(@NonNull Bundle outState) {
        dispatchActivityPreSaveInstanceState(outState);
        // 在这里执行Activity的状态保存的方法,也就是最上面看到的那个方法
        onSaveInstanceState(outState);
        saveManagedDialogs(outState);
        mActivityTransitionState.saveState(outState);
        storeHasCurrentPermissionRequest(outState);
        if (DEBUG_LIFECYCLE) Slog.v(TAG, "onSaveInstanceState " + this + ": " + outState);
        dispatchActivityPostSaveInstanceState(outState);
    }

或者是在ActivityThread的performStopActivityInner方法进行状态保存,最终依然是调用到ActivityThread#callActivityOnSaveInstanceState方法。

2.继续续分析onSaveInstanceState方法:

(1)FragmentActivity#onSaveInstanceState
    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        markFragmentsCreated();
        // 调用FragmentController的saveAllState保存状态,将状态数据保存在Parcelable对象中
        Parcelable p = mFragments.saveAllState();
        if (p != null) {
            outState.putParcelable(FRAGMENTS_TAG, p);
        }
        if (mPendingFragmentActivityResults.size() > 0) {
            outState.putInt(NEXT_CANDIDATE_REQUEST_INDEX_TAG, mNextCandidateRequestIndex);

            int[] requestCodes = new int[mPendingFragmentActivityResults.size()];
            String[] fragmentWhos = new String[mPendingFragmentActivityResults.size()];
            for (int i = 0; i < mPendingFragmentActivityResults.size(); i++) {
                requestCodes[i] = mPendingFragmentActivityResults.keyAt(i);
                fragmentWhos[i] = mPendingFragmentActivityResults.valueAt(i);
            }
            outState.putIntArray(ALLOCATED_REQUEST_INDICIES_TAG, requestCodes);
            outState.putStringArray(REQUEST_FRAGMENT_WHO_TAG, fragmentWhos);
        }
    }

在这里离,首先会调用FragmentController的saveAllState方法保存Fragment的当前的状态,而FragmentController的saveAllState方法的内部,其实是调用了HostCallbacks中的FragmentManager的saveAllState方法。

(2)FragmentManager#saveAllState
    Parcelable saveAllState() {
        // 确保所有待处理的操作已经获取到最新的状态信息
        // 该方法是将延迟队列中的事务出队并且启动
        forcePostponedTransactions();
        // 结束所有Fragment的动画
        endAnimatingAwayFragments();
        // 执行所有待处理的操作
        execPendingActions(true);

        // 修改状态标志,改成正在保存状态
        // 则在commit的时候,会调用checkStateLoss()方法判断是否正在做保存
        // 即在commit异步提交的时候,会执行到enqueueAction方法,然后根据标志位判断是否允许状态丢失
        // 如果是不允许,则会判断当前commit的时候是否正在做状态保存
        // 如果是正在做状态保存,则会抛出异常Can not perform this action after onSaveInstanceState
        mStateSaved = true;

        // 收集所有的活动Fragment,并且保存活动的Fragment的各种状态,比如View的状态等
        ArrayList<FragmentState> active = mFragmentStore.saveActiveFragments();

        if (active.isEmpty()) {
            if (isLoggingEnabled(Log.VERBOSE)) Log.v(TAG, "saveAllState: no fragments!");
            return null;
        }

        // 这里保存的其实是每个Fragment对应的标志id,其实就是Fragment中的mWho值
        ArrayList<String> added = mFragmentStore.saveAddedFragments();

        // 保存回退栈中的Fragment
        BackStackState[] backStack = null;
        if (mBackStack != null) {
            int size = mBackStack.size();
            if (size > 0) {
                backStack = new BackStackState[size];
                for (int i = 0; i < size; i++) {
                    backStack[i] = new BackStackState(mBackStack.get(i));
                    if (isLoggingEnabled(Log.VERBOSE)) {
                        Log.v(TAG, "saveAllState: adding back stack #" + i
                                + ": " + mBackStack.get(i));
                    }
                }
            }
        }
        // FragmentManagerState是Parcelable的接口实现类
        FragmentManagerState fms = new FragmentManagerState();
        fms.mActive = active;
        fms.mAdded = added;
        fms.mBackStack = backStack;
        fms.mBackStackIndex = mBackStackIndex.get();
        if (mPrimaryNav != null) {
            fms.mPrimaryNavActiveWho = mPrimaryNav.mWho;
        }
        return fms;
    }
(3)FragmentStore#saveActiveFragments
    @NonNull
    ArrayList<FragmentState> saveActiveFragments() {
        ArrayList<FragmentState> active = new ArrayList<>(mActive.size());
        for (FragmentStateManager fragmentStateManager : mActive.values()) {
            if (fragmentStateManager != null) {
                Fragment f = fragmentStateManager.getFragment();

                FragmentState fs = fragmentStateManager.saveState();
                active.add(fs);

                if (FragmentManager.isLoggingEnabled(Log.VERBOSE)) {
                    Log.v(TAG, "Saved state of " + f + ": " + fs.mSavedFragmentState);
                }
            }
        }
        return active;
    }
(4)FragmentStateManager#saveState
    @NonNull
    FragmentState saveState() {
        FragmentState fs = new FragmentState(mFragment);

        if (mFragment.mState > Fragment.INITIALIZING && fs.mSavedFragmentState == null) {
            // 这里就是保存Fragment的基本状态,比如View
            fs.mSavedFragmentState = saveBasicState();

            if (mFragment.mTargetWho != null) {
                if (fs.mSavedFragmentState == null) {
                    fs.mSavedFragmentState = new Bundle();
                }
                fs.mSavedFragmentState.putString(
                        TARGET_STATE_TAG,
                        mFragment.mTargetWho);
                if (mFragment.mTargetRequestCode != 0) {
                    fs.mSavedFragmentState.putInt(
                            TARGET_REQUEST_CODE_STATE_TAG,
                            mFragment.mTargetRequestCode);
                }
            }

        } else {
            fs.mSavedFragmentState = mFragment.mSavedFragmentState;
        }
        return fs;
    }
(5)FragmentStateManager#saveBasicState
    private Bundle saveBasicState() {
        Bundle result = new Bundle();
        // 这里是保存Fragment中的子Fragment的状态的
        mFragment.performSaveInstanceState(result);
        // 分发状态保存结果
        mDispatcher.dispatchOnFragmentSaveInstanceState(mFragment, result, false);
        if (result.isEmpty()) {
            result = null;
        }

        if (mFragment.mView != null) {
            // 保存View的状态
            saveViewState();
        }
        if (mFragment.mSavedViewState != null) {
            if (result == null) {
                result = new Bundle();
            }
            // 其实View的状态也是转成一个Parcelable
            // 并且保存在了一个SparseArray中,因为View会有子View
            result.putSparseParcelableArray(
                    VIEW_STATE_TAG, mFragment.mSavedViewState);
        }
        // 保存Fragment的显示状态
        if (!mFragment.mUserVisibleHint) {
            if (result == null) {
                result = new Bundle();
            }
            // Only add this if it's not the default value
            result.putBoolean(USER_VISIBLE_HINT_TAG, mFragment.mUserVisibleHint);
        }

        return result;
    }
(6)FragmentStateManager#saveViewState
    void saveViewState() {
        if (mFragment.mView == null) {
            return;
        }
        SparseArray<Parcelable> mStateArray = new SparseArray<>();
        // 这里其实是调用View的状态分发保存,将要保存状态的消息分发给其子View
        // 然后保存每个View的状态信息到mStateArray中。
        // 这里其实就是分别调用每一层级的View的onSaveInstanceState方法
        // 这样就可以将每个View视图保存成一个Parcelable,并且保存在对应的SparseArray集合中
        mFragment.mView.saveHierarchyState(mStateArray);
        if (mStateArray.size() > 0) {
            mFragment.mSavedViewState = mStateArray;
        }
    }
(7)View#saveHierarchyState
    public void saveHierarchyState(SparseArray<Parcelable> container) {
        dispatchSaveInstanceState(container);
    }
    protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) {
        if (mID != NO_ID && (mViewFlags & SAVE_DISABLED_MASK) == 0) {
            mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED;
            Parcelable state = onSaveInstanceState();
            if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) {
                throw new IllegalStateException(
                        "Derived class did not call super.onSaveInstanceState()");
            }
            if (state != null) {
                // Log.i("View", "Freezing #" + Integer.toHexString(mID)
                // + ": " + state);
                container.put(mID, state);
            }
        }
    }

3.Fragment的状态恢复

Fragment的状态恢复,其实是在FragmentActivity的onCreate刚执行的时候就会判断savedInstanceState是否不为null,然后进行恢复的。

相关文章

网友评论

      本文标题:Android-Fragment的状态保存和恢复

      本文链接:https://www.haomeiwen.com/subject/gcgxuktx.html