美文网首页
Activity状态的恢复和保存

Activity状态的恢复和保存

作者: 琼花落尽lxn | 来源:发表于2018-02-02 16:22 被阅读0次

    通常我们采用下面的方式保存Activity的状态

    @Override
    protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    }

    接下来我们从源码分析一下

    protected void onSaveInstanceState(Bundle outState) {
    //通知mWindow去保存层级状态
    outState.putBundle(WINDOW_HIERARCHY_TAG, mWindow.saveHierarchyState());
    outState.putInt(LAST_AUTOFILL_ID, mLastAutofillId);
    //保存Fragment的状态
    Parcelable p = mFragments.saveAllState();
    if (p != null) {
    //把数据放到Bundle里
    outState.putParcelable(FRAGMENTS_TAG, p);
    }
    if (mAutoFillResetNeeded) {
    outState.putBoolean(AUTOFILL_RESET_NEEDED, true);
    getAutofillManager().onSaveInstanceState(outState);
    }
    getApplication().dispatchActivitySaveInstanceState(this, outState);
    }

    我们知道mWindow是PhoneWindow的实例,下面去看看

    public Bundle saveHierarchyState() {
    Bundle outState = new Bundle();
    //mContentParent是DecorView中一个id为content的容器,我们Activitiy中的布局
    就是添加到这个mContent中
    if (mContentParent == null) {
    return outState;
    }
    //创建一个容器,用来保存View层级结构
    SparseArray<Parcelable> states = new SparseArray<Parcelable>();
    //保存View树状态
    mContentParent.saveHierarchyState(states);
    //将状态存到Bundle中
    outState.putSparseParcelableArray(VIEWS_TAG, states);

               // 保存有焦点的View
               View focusedView = mContentParent.findFocus();
               if (focusedView != null) {
                   if (focusedView.getId() != View.NO_ID) {
                       outState.putInt(FOCUSED_ID_TAG, focusedView.getId());
                   } else {
                       if (false) {
                           Log.d(TAG, "couldn't save which view has focus because the focused view "
                                   + focusedView + " has no id.");
                       }
                   }
               }
               return outState;
           }
    

    接下来我们看saveHierarchyState方法,由于ViewGroup没这个方法,所以我们去View里看

    public void saveHierarchyState(SparseArray<Parcelable> container) {
    dispatchSaveInstanceState(container);
    }

    protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) {
    //判断View是否有id以及是否允许保存
    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);
    //把结过放到容器中,键为View的id,值为状态
    container.put(mID, state);
    }
    }
    }

    从上面的代码可以看出,一个View如果想要保存状态,则必须提供一个id,并且它是允许状态保存的,我们可以通过setSaveEnabled方法来决定是否能够保存

    接下来我们看看ViewGroup的dispatchSaveInstanceState方法

    @Override
    protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) {
    super.dispatchSaveInstanceState(container);
    final int count = mChildrenCount;
    final View[] children = mChildren;
    for (int i = 0; i < count; i++) {
    View c = children[i];
    if ((c.mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED) {
    //保存每个子View的状态
    c.dispatchSaveInstanceState(container);
    }
    }
    }

    到此,整个View的保存状态就完了,接下来我i们看看Fragment的保存

    Parcelable p = mFragments.saveAllState();
    if (p != null) {
    outState.putParcelable(FRAGMENTS_TAG, p);
    }

    最终调用到了FragmentManagerImpl的saveAllState方法,,
    下面是精简后的代码

        if (mActive == null || mActive.size() <= 0) {
            return null;
        }
        
        //获得当前活动中的Fragment
        int N = mActive.size();
    

    //创建对应的Fragment状态数据
    FragmentState[] active = new FragmentState[N];
    boolean haveFragments = false;
    for (int i=0; i<N; i++) {
    //获取活动中的每个Fragment
    Fragment f = mActive.valueAt(i);
    if (f != null) {
    if (f.mIndex < 0) {
    throwException(new IllegalStateException(
    "Failure saving state: active " + f
    + " has cleared index: " + f.mIndex));
    }

                haveFragments = true;
                //创建每个Fragment对应的状态对象FragmentState 
                FragmentState fs = new FragmentState(f);
                active[i] = fs;
                
                if (f.mState > Fragment.INITIALIZING && fs.mSavedFragmentState == null) {
                  //代码1
                    fs.mSavedFragmentState = saveFragmentBasicState(f);
    
                    if (f.mTarget != null) {
                        if (f.mTarget.mIndex < 0) {
                            throwException(new IllegalStateException(
                                    "Failure saving state: " + f
                                    + " has target not in fragment manager: " + f.mTarget));
                        }
                        if (fs.mSavedFragmentState == null) {
                            fs.mSavedFragmentState = new Bundle();
                        }
                        putFragment(fs.mSavedFragmentState,
                                FragmentManagerImpl.TARGET_STATE_TAG, f.mTarget);
                        if (f.mTargetRequestCode != 0) {
                            fs.mSavedFragmentState.putInt(
                                    FragmentManagerImpl.TARGET_REQUEST_CODE_STATE_TAG,
                                    f.mTargetRequestCode);
                        }
                    }
    
                } else {
                    fs.mSavedFragmentState = f.mSavedFragmentState;
                }
                
                if (DEBUG) Log.v(TAG, "Saved state of " + f + ": "
                        + fs.mSavedFragmentState);
            }
        }
    

    在代码1处,把saveFragmentBasicState方法的返回值给了FragmentState对象的
    mSavedFragmentState属性,这个属性是一个Bundle对象,下面我们看看saveFragmentBasicState方法

    Bundle saveFragmentBasicState(Fragment f) {
    Bundle result = null;

        if (mStateBundle == null) {
            mStateBundle = new Bundle();
        }
    

    //代码2,调用Fragment对象的performSaveInstanceState方法
    f.performSaveInstanceState(mStateBundle);
    dispatchOnFragmentSaveInstanceState(f, mStateBundle, false);
    if (!mStateBundle.isEmpty()) {
    result = mStateBundle;
    mStateBundle = null;
    }

        if (f.mView != null) {
    

    //保存Fragment视图数结构
    saveFragmentViewState(f);
    }
    if (f.mSavedViewState != null) {
    if (result == null) {
    result = new Bundle();
    }
    //将上面保存的视图树的结果放到Bundle中
    result.putSparseParcelableArray(
    FragmentManagerImpl.VIEW_STATE_TAG, f.mSavedViewState);
    }
    if (!f.mUserVisibleHint) {
    if (result == null) {
    result = new Bundle();
    }
    // Only add this if it's not the default value
    result.putBoolean(FragmentManagerImpl.USER_VISIBLE_HINT_TAG, f.mUserVisibleHint);
    }

        return result;
    }
    

    代码2处条用了Fragment的一个方法,如下

    void performSaveInstanceState(Bundle outState) {
    

    //执行Fragment的onSaveInstanceState方法,这是一个空方法
    onSaveInstanceState(outState);
    if (mChildFragmentManager != null) {
    Parcelable p = mChildFragmentManager.saveAllState();
    if (p != null) {
    outState.putParcelable(FragmentActivity.FRAGMENTS_TAG, p);
    }
    }
    }

    下面我们看保存Fragment视图数结构的代码

    void saveFragmentViewState(Fragment f) {
    if (f.mView == null) {
    return;
    }
    if (mStateArray == null) {
    mStateArray = new SparseArray<Parcelable>();
    } else {
    mStateArray.clear();
    }
    //和上面View的保存状态一样
    f.mView.saveHierarchyState(mStateArray);
    if (mStateArray.size() > 0) {
    f.mSavedViewState = mStateArray;
    mStateArray = null;
    }
    }

    总结

    通过上面的分析,我们发现在saveFragmentBasicState中主要做了两件事,
    1.保存Fragment的数据
    2.保存Fragment视图树结构

    然后把这些数据给了FragmentState的一个Bundle属性,所以FragmentState这个对象对Fragment的状态保存很重要。

    状态恢复源码分析

    我们看Activity的onRestoreInstanceState方法

    protected void onRestoreInstanceState(Bundle savedInstanceState) {
    if (mWindow != null) {
    //获取保存的视图树信息
    Bundle windowState = savedInstanceState.getBundle(WINDOW_HIERARCHY_TAG);
    if (windowState != null) {

    //调用PhoneWindow的restoreHierarchyState方法
    mWindow.restoreHierarchyState(windowState);
    }
    }
    }

    PhoneWindow的方法
    @Override
    public void restoreHierarchyState(Bundle savedInstanceState) {
    if (mContentParent == null) {
    return;
    }
    //获取保存的状态信息
    SparseArray<Parcelable> savedStates
    = savedInstanceState.getSparseParcelableArray(VIEWS_TAG);
    if (savedStates != null) {
    mContentParent.restoreHierarchyState(savedStates);
    }

        // restore the focused view
        int focusedViewId = savedInstanceState.getInt(FOCUSED_ID_TAG, View.NO_ID);
        if (focusedViewId != View.NO_ID) {
            View needsFocus = mContentParent.findViewById(focusedViewId);
            if (needsFocus != null) {
                needsFocus.requestFocus();
            } else {
                Log.w(TAG,
                        "Previously focused view reported id " + focusedViewId
                                + " during save, but can't be found during restore.");
            }
        }
    

    调用了View的方法

    public void restoreHierarchyState(SparseArray<Parcelable> container) {
    dispatchRestoreInstanceState(container);
    }

    protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) {
    //判断当前View是否有id
    if (mID != NO_ID) {
    //根据id获取对应的数据
    Parcelable state = container.get(mID);
    if (state != null) {
    // Log.i("View", "Restoreing #" + Integer.toHexString(mID)
    // + ": " + state);
    mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED;
    //恢复数据
    onRestoreInstanceState(state);
    if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) {
    throw new IllegalStateException(
    "Derived class did not call super.onRestoreInstanceState()");
    }
    }
    }
    }

    恢复Fragment状态,我们看看Activity的onCreate方法
    protected void onCreate(@Nullable Bundle savedInstanceState) {

    if (savedInstanceState != null) {
    //获取Fragment的数据
    Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);
    mFragments.restoreAllState(p, mLastNonConfigurationInstances != null
    ? mLastNonConfigurationInstances.fragments : null);
    }
    mFragments.dispatchCreate();
    getApplication().dispatchActivityCreated(this, savedInstanceState);

    下面我们看看restoreAllState方法,这个方法定义在FragmentManager中

    void restoreAllState(Parcelable state, FragmentManagerNonConfig nonConfig) {
    if (state == null) return;
    FragmentManagerState fms = (FragmentManagerState)state;
    if (fms.mActive == null) return;

    for (int i=0; i<fms.mActive.length; i++) {
    //获取Fragment的状态数据
    FragmentState fs = fms.mActive[i];
    Fragment f = fs.instantiate(mHost, mContainer, mParent, childNonConfig);
    if (DEBUG) Log.v(TAG, "restoreAllState: active #" + i + ": " + f);
    mActive.put(f.mIndex, f);
    // Now that the fragment is instantiated (or came from being
    // retained above), clear mInstance in case we end up re-restoring
    // from this FragmentState again.
    fs.mInstance = null;
    }

    我们去看FragmentState的instantiate方法

    public Fragment instantiate(FragmentHostCallback host, FragmentContainer container,
    Fragment parent, FragmentManagerNonConfig childNonConfig) {
    if (mInstance == null) {
    final Context context = host.getContext();
    if (mArguments != null) {
    mArguments.setClassLoader(context.getClassLoader());
    }

            if (container != null) {
                mInstance = container.instantiate(context, mClassName, mArguments);
            } else {
            //初始化Fragment
                mInstance = Fragment.instantiate(context, mClassName, mArguments);
            }
        //把之前保存的状态信息赋值给新建的对象
            if (mSavedFragmentState != null) {
                mSavedFragmentState.setClassLoader(context.getClassLoader());
                mInstance.mSavedFragmentState = mSavedFragmentState;
            }
            mInstance.setIndex(mIndex, parent);
            mInstance.mFromLayout = mFromLayout;
            mInstance.mRestored = true;
            mInstance.mFragmentId = mFragmentId;
            mInstance.mContainerId = mContainerId;
            mInstance.mTag = mTag;
            mInstance.mRetainInstance = mRetainInstance;
            mInstance.mDetached = mDetached;
            mInstance.mHidden = mHidden;
            mInstance.mFragmentManager = host.mFragmentManager;
            if (FragmentManagerImpl.DEBUG) Log.v(FragmentManagerImpl.TAG,
                    "Instantiated fragment " + mInstance);
        }
        mInstance.mChildNonConfig = childNonConfig;
        return mInstance;
    }
    

    这里只是恢复了Fragment的一部分的数据,View视图树还没创建,所以别的数据是在Fragment进入生命周期才恢复的,我们再回到Activity的onCreate中,调用了
    mFragments.dispatchCreate();方法,此时调用的是FragmentManager的方法

    public void dispatchCreate() {
    mStateSaved = false;
    dispatchMoveToState(Fragment.CREATED);
    }

    private void dispatchMoveToState(int state) {
    if (mAllowOldReentrantBehavior) {
    moveToState(state, false);
    } else {
    try {
    mExecutingActions = true;
    moveToState(state, false);
    } finally {
    mExecutingActions = false;
    }
    }
    execPendingActions();
    }

    然后看moveToState方法
    void moveToState(int newState, boolean always) {
    if (mAdded != null) {
    final int numAdded = mAdded.size();
    for (int i = 0; i < numAdded; i++) {
    Fragment f = mAdded.get(i);
    //看此方法
    moveFragmentToExpectedState(f);
    if (f.mLoaderManager != null) {
    loadersRunning |= f.mLoaderManager.hasRunningLoaders();
    }
    }
    }
    }

    void moveFragmentToExpectedState(final Fragment f) {
    if (f == null) {
    return;
    }
    int nextState = mCurState;
    if (f.mRemoving) {
    if (f.isInBackStack()) {
    nextState = Math.min(nextState, Fragment.CREATED);
    } else {
    nextState = Math.min(nextState, Fragment.INITIALIZING);
    }
    }
    //看此方法
    moveToState(f, nextState, f.getNextTransition(), f.getNextTransitionStyle(), false);

    在moveToState方法里调用了下面的方法
    //调用Fragment的onActivityCreated方法
    f.performActivityCreated(f.mSavedFragmentState);
    dispatchOnFragmentActivityCreated(f, f.mSavedFragmentState, false);
    if (f.mView != null) {
    //恢复Fragment视图状态
    f.restoreViewState(f.mSavedFragmentState);
    }
    f.mSavedFragmentState = null;
    }

    从上面的代码我们可以看出,恢复Fragment视图数据的时机是在onActivityCreated方法之后,

    final void restoreViewState(Bundle savedInstanceState) {
    if (mSavedViewState != null) {
    //恢复View树状态
    mView.restoreHierarchyState(mSavedViewState);
    mSavedViewState = null;
    }
    mCalled = false;
    onViewStateRestored(savedInstanceState);
    if (!mCalled) {
    throw new SuperNotCalledException("Fragment " + this
    + " did not call through to super.onViewStateRestored()");
    }
    }

    @CallSuper
    public void onViewStateRestored(Bundle savedInstanceState) {
    mCalled = true;
    }

    总结

    在Fragment中我们可以通过onSaveInstanceState方法保存数据,需要注意的是,Fragment并没有onRestoreInStanceState方法,我们一般重写onViewStateRestored方法恢复数据

    相关文章

      网友评论

          本文标题:Activity状态的恢复和保存

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