Fragment相关源码解析二——生命周期

上次说到BackStackRecord的一系列操作其实是在内部形成了一个Op双向链表,commit() 方法调用后被加入到了FragmentManagerImpl的List中,随后会调用BackStackRecord的run()方法。在看这个方法之前我们首先要明确几件事情。

Fragment的mState

它代表了Fragment的状态,可能被赋值为如下几个值,被初始化的时候默认是INITIALIZING的。

    //Fragment.java
    static final int INITIALIZING = 0;     // Not yet created.
    static final int CREATED = 1;          // Created.
    static final int ACTIVITY_CREATED = 2; // The activity has finished its creation.
    static final int STOPPED = 3;          // Fully created, not started.
    static final int STARTED = 4;          // Created and started, not resumed.
    static final int RESUMED = 5;          // Created started and resumed.
    
    int mState = INITIALIZING;

FragmentManagerImpl的mCurState

FragmentManagerImpl内部也维护了一个状态来表示Fragment的状态,它在FragmentActivity的生命周期回调时被赋值为相应的状态。

//FragmentManagerImpl.java
int mCurState = Fragment.INITIALIZING;

FragmentActivity的生命周期回调会对Fragment产生影响

FragmentActivity的一系列生命周期回调都会在内部调用mFragments的相应方法。

  //FragmentActivity.java    
  protected void onCreate(@Nullable Bundle savedInstanceState) {
          .....
          mFragments.dispatchCreate();
  }

    protected void onStart() {
        .....

        mFragments.dispatchStart();
        .....
    }

我们知道最终会调用到FragmentManagerImpl的相应方法。最后会调用moveToState 并传入不同的Fragment状态,这里对所有其管辖的Fragment进行了状态转移。那么也就是说Fragment的状态改变可能源自两种情况:1.FragmentActivity的生命周期回调。2.BackStackRecord事务的提交。

//FragmentManagerImpl.java
    public void dispatchCreate() {
        mStateSaved = false;
        moveToState(Fragment.CREATED, false);
    }
    
    public void dispatchActivityCreated() {
        mStateSaved = false;
        moveToState(Fragment.ACTIVITY_CREATED, false);
    }
    
    public void dispatchStart() {
        mStateSaved = false;
        moveToState(Fragment.STARTED, false);
    }
    
    public void dispatchResume() {
        mStateSaved = false;
        moveToState(Fragment.RESUMED, false);
    }
    
    public void dispatchPause() {
        moveToState(Fragment.STARTED, false);
    }

BackStackRecord的run()

从整体上来看做了如下几件事情:(1)如果该事务添加到了回退栈,为其Op链中每个Fragment的被回退栈事务引用数加1。(2)遍历该事务的Op链,根据每个Op节点的op.cmd调用FragmentManagerImpl相应的方法。(3)检查完Op链后,要将所有Fragment的状态统一成当前FragmentManagerImpl维护的状态。(4)如果事务最后调用了addToBackStack(),则将该事务添加到回退栈的列表,并调用相应回调函数。

 //BackStackRecord.java
    public void run() {
        .....
        //如果该事务添加到了回退栈,为其Op链中每个Fragment的相应值加1,表示Fragment被回退栈中的事务引用的次数
        bumpBackStackNesting(1);
        ...
         //遍历Op链,根据op.cmd执行相应的操作
        Op op = mHead;
        while (op != null) {
            int enterAnim = state != null ? 0 : op.enterAnim;
            int exitAnim = state != null ? 0 : op.exitAnim;
            switch (op.cmd) {
                case OP_ADD: {
                    Fragment f = op.fragment;
                    f.mNextAnim = enterAnim;
                    mManager.addFragment(f, false);
                } break;
                ...
                case OP_HIDE: {
                    Fragment f = op.fragment;
                    f.mNextAnim = exitAnim;
                    mManager.hideFragment(f, transition, transitionStyle);
                } break;
                ....
                case OP_ATTACH: {
                    Fragment f = op.fragment;
                    f.mNextAnim = enterAnim;
                    mManager.attachFragment(f, transition, transitionStyle);
                } break;
                ...
            }

            op = op.next;
        }
        //检查完Op链后,要将所有Fragment的状态统一成当前FragmentManagerImpl维护的状态
        mManager.moveToState(mManager.mCurState, transition, transitionStyle, true);
        //如果调用了addToBackStack()
        if (mAddToBackStack) {
            mManager.addBackStackState(this);
        }
    }

我们看一下FragmentManagerImpl的一系列xxxFragment()方法中典型的几个,以窥这些方法的大致逻辑。

对于addFragment() ,makeActive(fragment)首先给Fragment分配了mIndex,这是代表已经提交的事务中该Fragment在FragmentManagerImpl(mActive)中的唯一index。在mAdded中添加了该Fragment。为Fragment的mAdded和mRemoving赋值。

    //FragmentManagerImpl.java
    public void addFragment(Fragment fragment, boolean moveToStateNow) {
        if (mAdded == null) {
            mAdded = new ArrayList<Fragment>();
        }
        if (DEBUG) Log.v(TAG, "add: " + fragment);
        //为Fragment分配index
        makeActive(fragment);
        if (!fragment.mDetached) {
            if (mAdded.contains(fragment)) {
                throw new IllegalStateException("Fragment already added: " + fragment);
            }
            mAdded.add(fragment);
            fragment.mAdded = true;
            fragment.mRemoving = false;
            if (fragment.mHasMenu && fragment.mMenuVisible) {
                mNeedMenuInvalidate = true;
            }
            if (moveToStateNow) {
                moveToState(fragment);
            }
        }
    }

对于removeFragment() ,见注释。

    //FragmentManagerImpl.java
    public void removeFragment(Fragment fragment, int transition, int transitionStyle) {
        if (DEBUG) Log.v(TAG, "remove: " + fragment + " nesting=" + fragment.mBackStackNesting);
        //是否被回退栈中的事务引用(也就是是否调用了addToBackStack()),没被引用返回true。
        final boolean inactive = !fragment.isInBackStack();
        //如果不是detached状态或被引用了
        if (!fragment.mDetached || inactive) {
            //mAdded列表中移除该
            if (mAdded != null) {
                mAdded.remove(fragment);
            }
            if (fragment.mHasMenu && fragment.mMenuVisible) {
                mNeedMenuInvalidate = true;
            }
            fragment.mAdded = false;
            fragment.mRemoving = true;
            //如果没在回退栈中被引用,传入INITIALIZING;如果被引用了,传入CREATED。
          //对于moveToState,传入不同的参数会影响Fragment生命周期的回调
          //这里关系到Fragment是否会回调onDestroy和onDetach方法,后面再细说。
            moveToState(fragment, inactive ? Fragment.INITIALIZING : Fragment.CREATED,
                    transition, transitionStyle, false);
        }
    }

看到这里我们知道知道FragmentManagerImpl的xxxFragment()方法都是根据当前Fragment的状态进行一系列在FragmentManagerImpl列表中的添加和删除以及Fragment本身状态的设置等,最后还可能调用FragmentManagerImpl的moveToState() 。

无论在遍历Op链的阶段是否会调用moveToState() (5参,进行单个Fragment的生命周期同步),BackStackRecord的run()都会调用moveToState() (4参,间接调用5参,对所有Fragment进行生命周期同步)。这个方法是FragmentManagerImpl对Fragment进行生命周期管理的重要方法。接下来我们重点看一下这个方法。

FragmentManagerImpl的5参moveToState()

// FragmentManagerImpl

void moveToState(Fragment f)
void moveToState(int newState, boolean always)
void moveToState(int newState, int transit, int transitStyle, boolean always)
void moveToState(Fragment f, int newState, int transit, int transitionStyle,boolean keepActive)

有四种重载,最终都会和5参的函数相关,我们来看一下。

这个方法很长,先从整体上对它进行一个了解。

除去开头的一些判断,整体上分为两种情况:Fragment的状态小于newState和Fragment的状态大于newState。switch是没有break的,而在其中的Fragment的生命周期回调会给Fragment的赋新的状态值,也就是说Fragment的会一直回调相应的生命周期方法直到其mState达到了newState。

//FragmentManagerImpl # moveToState()
if (f.mState < newState) {
  switch (f.mState) {
                case Fragment.INITIALIZING:
                    ....
                      f.onAttach(mHost.getContext());
                case Fragment.CREATED:
                    if (newState > Fragment.CREATED) {
                        ...    
                    }
} else if (f.mState > newState) {
  ...
}

如果newState大于Fragment状态,Fragment会不断进行状态升级,如果newState小于Fragment状态,Fragment会不断进行状态下降。进入每一个case来观察,以一个Fragment从创建到可见,再从可见到销毁为例,大致的流程如下(假设是动态添加Fragment,没被添加到回退栈也没有调用setRetainInstance ):

一个Fragment从创建到RESUMED,它的状态变化和在相应状态的回调函数如下:

INITIALIZING(onAttach、onCreate) -> CREATED(onCreateView、onActivityCreated) -> ACTIVITY_CREATED(onStart ) -> STARTED(onResume ) -> RESUMED

而一个Fragment从RESUMED到被销毁,它的状态变化和在相应状态的回调函数如下:

RESUMED(onPause) -> STARTED(onStop) -> STOPPED(状态赋值为ACTIVITY_CREATED) -> ACTIVITY_CREATED(onDestroyView) -> CREATED(onDestroy、onDetach) -> INITIALIZING

形成一张表如下(注意这里依然没有考虑静态加载、添加到回退栈、setRetainInstance等情况):

起始状态 经历回调函数 回调后状态
INITIALIZING onAttach、onCreate CREATED
CREATED onCreateView、onActivityCreated ACTIVITY_CREATED(STOPPED)
ACTIVITY_CREATED(STOPPED) onStart STARTED
STARTED onResume RESUMED
RESUMED onPause STARTED
STARTED onStop STOPPED
STOPPED 状态赋值为ACTIVITY_CREATED ACTIVITY_CREATED
ACTIVITY_CREATED onDestroyView CREATED
CREATED onDestroy、onDetach INITIALIZING

借用网上的一个生命周期转移图,如果你理解了moveToState 中Fragment的状态转移和生命周期回调,那么这张图会更加加深你的理解。


这里写图片描述

下面贴出moveToState 的完整源码,在关键的地方都给出了注释,当然,由于本人水平非常有限,对于Animation还有LoaderManager这样的地方还无法做到完全理解,只能把自己已经理解的东西写上去,大家各取所需。

//FragmentManagerImpl.java
void moveToState(Fragment f, int newState, int transit, int transitionStyle,
            boolean keepActive) {
        // Fragments that are not currently added will sit in the onCreate() state.
     // 如果当前Fragment的状态并不是ADD状态,或者已经detach,
    // 此时设置的newState比如start等会统一修改为CREATED状态,让Fragment仍停留在create状态
        if ((!f.mAdded || f.mDetached) && newState > Fragment.CREATED) {
            newState = Fragment.CREATED;
        }
        // 当一个fragment正在被remove,该fragment应该保持原来的状态
        if (f.mRemoving && newState > f.mState) {
            // While removing a fragment, we can't change it to a higher state.
            newState = f.mState;
        }
        
        //可以理解为延迟开始的标识,如果当前Fragment的状态还没有走到Fragment.STARTED,那么当mDeferStart为true时,Fragment的状态最多只能到Fragment.STOPPED,无法通过moveToState继续切换到Fragment.STARTED
  // Defer start if requested; don't allow it to move to STARTED or higher
        // if it's not already started.
        if (f.mDeferStart && f.mState < Fragment.STARTED && newState > Fragment.STOPPED) {
            newState = Fragment.STOPPED;
        }
  
        //升级状态,让Fragment状态同步到newState
        if (f.mState < newState) {
          //因为静态创建和动态创建的时机不一样,我们不想在重新恢复时,Fragment的视图优先于Activity创建(onCreate中会恢复Fragment,而静态的Fragment会在INITIALIZING就恢复View,此时还没执行到Activity的setContentView,mInLayout默认为true,但在状态保存时被置为false)
            // For fragments that are created from a layout, when restoring from
            // state we don't want to allow them to be created until they are
            // being reloaded from the layout.
            if (f.mFromLayout && !f.mInLayout) {
                return;
            }  
          //在切换为最新状态前,动画会被直接忽视掉并直接先把状态切换到动画结束时应该切换到的状态,以走完上次未走完的流程
            if (f.mAnimatingAway != null) {
                // The fragment is currently being animated...  but!  Now we
                // want to move our state back up.  Give up on waiting for the
                // animation, move to whatever the final state should be once
                // the animation is done, and then we can proceed from there.
                f.mAnimatingAway = null;
                moveToState(f, f.mStateAfterAnimating, 0, 0, true);
            }
            switch (f.mState) {
                case Fragment.INITIALIZING:
                    if (DEBUG) Log.v(TAG, "moveto CREATED: " + f);
                    //如果是销毁重建,用mSavedFragmentState为Fragment恢复了包括mSavedViewState 、mTarget 、mTargetRequestCode 、mUserVisibleHint的状态。mSavedFragmentState是FragmentState中的一个Bundle,用来持久化一些除了基本状态外的额外数据
                    if (f.mSavedFragmentState != null) {
                        f.mSavedFragmentState.setClassLoader(mHost.getContext().getClassLoader());
                        f.mSavedViewState = f.mSavedFragmentState.getSparseParcelableArray(
                                FragmentManagerImpl.VIEW_STATE_TAG);
                        f.mTarget = getFragment(f.mSavedFragmentState,
                                FragmentManagerImpl.TARGET_STATE_TAG);
                        if (f.mTarget != null) {
                            f.mTargetRequestCode = f.mSavedFragmentState.getInt(
                                    FragmentManagerImpl.TARGET_REQUEST_CODE_STATE_TAG, 0);
                        }
                        f.mUserVisibleHint = f.mSavedFragmentState.getBoolean(
                                FragmentManagerImpl.USER_VISIBLE_HINT_TAG, true);
                        if (!f.mUserVisibleHint) {
                            f.mDeferStart = true;
                            if (newState > Fragment.STOPPED) {
                                newState = Fragment.STOPPED;
                            }
                        }
                    }
                
                    //为设置一些参数
                    f.mHost = mHost;
                    f.mParentFragment = mParent;
                    f.mFragmentManager = mParent != null
                            ? mParent.mChildFragmentManager : mHost.getFragmentManagerImpl();
                    f.mCalled = false;
                    //回调生命周期方法onAttach()
                    f.onAttach(mHost.getContext());
                    if (!f.mCalled) {
                        throw new SuperNotCalledException("Fragment " + f
                                + " did not call through to super.onAttach()");
                    }
                    if (f.mParentFragment == null) {
                        mHost.onAttachFragment(f);
                    }
                   //如果mRetaining字段不为true,也就是没有调用setRetainInstance方法,需回调生命周期方法onCreate(),并将状态状态设置为CREATED
                    if (!f.mRetaining) {
                        f.performCreate(f.mSavedFragmentState);
                    }
                    f.mRetaining = false;
                    //如果是静态加载,我们需要立即初始化View
                    if (f.mFromLayout) {
                        
                        //回调onCreateView()
                        f.mView = f.performCreateView(f.getLayoutInflater(
                                f.mSavedFragmentState), null, f.mSavedFragmentState);
                        
                        if (f.mView != null) {
                            f.mInnerView = f.mView;
                            if (Build.VERSION.SDK_INT >= 11) {
                                ViewCompat.setSaveFromParentEnabled(f.mView, false);
                            } else {
                                f.mView = NoSaveStateFrameLayout.wrap(f.mView);
                            }
                            if (f.mHidden) f.mView.setVisibility(View.GONE);
                            //回调onViewCreated()
                            f.onViewCreated(f.mView, f.mSavedFragmentState);
                        } else {
                            f.mInnerView = null;
                        }
                    }
                case Fragment.CREATED:
                    if (newState > Fragment.CREATED) {
                        if (DEBUG) Log.v(TAG, "moveto ACTIVITY_CREATED: " + f);
                        //如果不是静态加载
                        if (!f.mFromLayout) {
                            ViewGroup container = null;
                            if (f.mContainerId != 0) {
                                //获取Fragment的container
                                container = (ViewGroup)mContainer.onFindViewById(f.mContainerId);
                                if (container == null && !f.mRestored) {
                                    throwException(new IllegalArgumentException(
                                            "No view found for id 0x"
                                            + Integer.toHexString(f.mContainerId) + " ("
                                            + f.getResources().getResourceName(f.mContainerId)
                                            + ") for fragment " + f));
                                }
                            }
                            f.mContainer = container;
                            //回调onCreateView(),创建Fragment的视图
                            f.mView = f.performCreateView(f.getLayoutInflater(
                                    f.mSavedFragmentState), container, f.mSavedFragmentState);
                            if (f.mView != null) {
                                f.mInnerView = f.mView;
                                if (Build.VERSION.SDK_INT >= 11) {
                                  //对传入的View参数,关闭其层级开始及其以下所有的子View的保存状态不再受其parent的控制;
                                    ViewCompat.setSaveFromParentEnabled(f.mView, false);
                                } else {
                                    f.mView = NoSaveStateFrameLayout.wrap(f.mView);
                                }
                                if (container != null) {
                                    Animation anim = loadAnimation(f, transit, true,
                                            transitionStyle);
                                    if (anim != null) {
                                        setHWLayerAnimListenerIfAlpha(f.mView, anim);
                                        f.mView.startAnimation(anim);
                                    }
                                    //将f.mView添加到container中
                                    container.addView(f.mView);
                                }
                                //如果隐藏,则不显示Fragment
                                if (f.mHidden) f.mView.setVisibility(View.GONE);
                                //回调onViewCreated()
                                f.onViewCreated(f.mView, f.mSavedFragmentState);
                            } else {
                                f.mInnerView = null;
                            }
                        }
                      //回调onActivityCreated(),并将状态设置为ACTIVITY_CREATED
                        f.performActivityCreated(f.mSavedFragmentState);
                        //在这里利用持久化的mSavedFragmentState恢复了View树的状态
                        if (f.mView != null) {
                            f.restoreViewState(f.mSavedFragmentState);
                        }
                        f.mSavedFragmentState = null;
                    }
                case Fragment.ACTIVITY_CREATED:
                case Fragment.STOPPED:
                    if (newState > Fragment.STOPPED) {
                        if (DEBUG) Log.v(TAG, "moveto STARTED: " + f);
                        //回调onStart(),并将状态设置为STARTED
                        f.performStart();
                    }
                case Fragment.STARTED:
                    if (newState > Fragment.STARTED) {
                        if (DEBUG) Log.v(TAG, "moveto RESUMED: " + f);
                      //回调onResume(),并将状态设置为RESUMED
                        f.performResume();
                        f.mSavedFragmentState = null;
                        f.mSavedViewState = null;
                    }
            }
        } else if (f.mState > newState) {//降级同步
            
            switch (f.mState) {
                case Fragment.RESUMED:
                    if (newState < Fragment.RESUMED) {
                        if (DEBUG) Log.v(TAG, "movefrom RESUMED: " + f);
                      //回调onPause(),并将状态设置为STARTED
                        f.performPause();
                    }
                case Fragment.STARTED:
                    if (newState < Fragment.STARTED) {
                        if (DEBUG) Log.v(TAG, "movefrom STARTED: " + f);
                        //回调onStop(),并将状态设置为STOPPED
                        f.performStop();
                    }
                case Fragment.STOPPED:
                    if (newState < Fragment.STOPPED) {
                        if (DEBUG) Log.v(TAG, "movefrom STOPPED: " + f);
                        //将状态设置为ACTIVITY_CREATED,并调用了mLoaderManager的一些方法
                        f.performReallyStop();
                    }
                case Fragment.ACTIVITY_CREATED:
                    if (newState < Fragment.ACTIVITY_CREATED) {
                        if (DEBUG) Log.v(TAG, "movefrom ACTIVITY_CREATED: " + f);
                        if (f.mView != null) {
                            //如果当前状态是ACTIVITY_CREATED且还需要降级,此时如果需要保存View的状态(有几种情况,具体看下一篇),那么保存View树状态。
                            if (mHost.onShouldSaveFragmentState(f) && f.mSavedViewState == null) {
                                saveFragmentViewState(f);
                            }
                        }
                      //回调onDestroyView(),并将状态设置为CREATED
                        f.performDestroyView();
                        if (f.mView != null && f.mContainer != null) {
                            Animation anim = null;
                            if (mCurState > Fragment.INITIALIZING && !mDestroyed) {
                              // loadAnimation根据fragment.mNextAnim,transit和transitionStyle三个条件返回一个anim
                                anim = loadAnimation(f, transit, false,
                                        transitionStyle);
                            }
                            if (anim != null) {
                                final Fragment fragment = f;
                              // anim不为null表示指定了动画,所以mAnimatingAway被赋值为了Fragment的布局文件
                                f.mAnimatingAway = f.mView;
                              // 并将Fragment需要move to的新状态保存在mStateAfterAnimating中
                                f.mStateAfterAnimating = newState;
                                final View viewToAnimate = f.mView;
                              // 对动画设置监听
                                anim.setAnimationListener(new AnimateOnHWLayerIfNeededListener(
                                        viewToAnimate, anim) {
                                    @Override
                                    public void onAnimationEnd(Animation animation) {
                                        super.onAnimationEnd(animation);
                                      // 当动画结束,才开始继续进行下一步的状态更新操作,并清空mAnimatingAway
                    // 移动的新状态就是动画开始前临时保存在mStateAfterAnimating的状态
                                        if (fragment.mAnimatingAway != null) {
                                            fragment.mAnimatingAway = null;
                                            moveToState(fragment, fragment.mStateAfterAnimating,
                                                    0, 0, false);
                                        }
                                    }
                                });
                              // 然后对整个布局文件开始动画
                                f.mView.startAnimation(anim);
                            }
                          // 不论是否有动画,Fragment所属视图在performDestroyView()后就立即被移除了
                            f.mContainer.removeView(f.mView);
                        }
                        //将View相关变量置空,交给系统回收
                        f.mContainer = null;
                        f.mView = null;
                        f.mInnerView = null;
                    }
                case Fragment.CREATED:
                    if (newState < Fragment.CREATED) {
                        if (mDestroyed) {
                          // 如果动画期间宿主Activity需要destroy了,那么就不应该还要等到Fragment的动画完成的才结束
            // 而是直接cancel掉(不会回调onAnimationEnd),并清除mAnimatingAway标识以正常状态流程切换。
                            if (f.mAnimatingAway != null) {
                                // The fragment's containing activity is
                                // being destroyed, but this fragment is
                                // currently animating away.  Stop the
                                // animation right now -- it is not needed,
                                // and we can't wait any more on destroying
                                // the fragment.
                                View v = f.mAnimatingAway;
                                f.mAnimatingAway = null;
                                v.clearAnimation();
                            }
                        }
                      // 表示正在执行退出动画,只需等待,
        // 同时更新f.mStateAfterAnimating为最新状态以让动画结束时Fragment能同步至最新状态
                        if (f.mAnimatingAway != null) {
                            // We are waiting for the fragment's view to finish
                            // animating away.  Just make a note of the state
                            // the fragment now should move to once the animation
                            // is done.
                            f.mStateAfterAnimating = newState;
                            newState = Fragment.CREATED;
                        } else {// 否则根据正常流程条件依次执行destroy、dettach
                            if (DEBUG) Log.v(TAG, "movefrom CREATED: " + f);
                            //如果并不需要保存实例
                            if (!f.mRetaining) {
                                //回调onDestroy(),并将状态设置为INITIALIZING
                                f.performDestroy();
                            } else {
                                f.mState = Fragment.INITIALIZING;
                            }
                            
                            f.mCalled = false;
                            //回调onDetach()
                            f.onDetach();
                            if (!f.mCalled) {
                                throw new SuperNotCalledException("Fragment " + f
                                        + " did not call through to super.onDetach()");
                            }
                            if (!keepActive) {
                                if (!f.mRetaining) {
                                    //释放index,并把该Fragment的一些基本变量初始化为默认值
                                    makeInactive(f);
                                } else {
                                    f.mHost = null;
                                    f.mParentFragment = null;
                                    f.mFragmentManager = null;
                                    f.mChildFragmentManager = null;
                                }
                            }
                        }
                    }
            }
        }

        if (f.mState != newState) {
            Log.w(TAG, "moveToState: Fragment state for " + f + " not updated inline; "
                    + "expected state " + newState + " found " + f.mState);
            f.mState = newState;
        }
    }

一些细节

addToBackStack()的影响

当我们调用了BackSatckRecord#addToBackStack() ,只是把mAddToBackStack赋值为true。

    //BackSatckRecord.java
    public FragmentTransaction addToBackStack(String name) {
        if (!mAllowAddToBackStack) {
            throw new IllegalStateException(
                    "This FragmentTransaction is not allowed to be added to the back stack.");
        }
        mAddToBackStack = true;
        mName = name;
        return this;
    }

commit() 之后,最后在run() 中会受到影响,如果mAddToBackStack为true,那么bumpBackStackNesting(1)会将事务中涉及到的Fragment的mBackStackNesting加1(这个值将会影响Fragment#isInBackStack() 的返回值),接着将这个事务添加到了回退栈中。

    //BackSatckRecord.java
    public void run() {
        ...
        bumpBackStackNesting(1);
        ...
        if (mAddToBackStack) {
            mManager.addBackStackState(this);
        }
    }

我们关注一下FragmentManagerImpl#removeFragment() ,如果事务被添加到了回退栈,且事务中Fragment被移除,这个Fragment的状态最终会更新到CREATED,只会执行到onDestroyView,不会执行onDestroy和onDetach。

    //FragmentManagerImpl.java
    public void removeFragment(Fragment fragment, int transition, int transitionStyle) {
        ...
        final boolean inactive = !fragment.isInBackStack();
        if (!fragment.mDetached || inactive) {
            ....
            moveToState(fragment, inactive ? Fragment.INITIALIZING : Fragment.CREATED,
                    transition, transitionStyle, false);
        }
    }

紧接着按了返回键。

 //FragmentActivity.java
    public void onBackPressed() {
        if (!mFragments.getSupportFragmentManager().popBackStackImmediate()) {
            onBackPressedNotHandled();
        }
    }

最终调用到下面这个方法,看一下第一个if里面,从回退栈中出栈了一个事务,并调用了popFromBackStack 。

//FragmentManagerImpl.java
@SuppressWarnings("unused")
    boolean popBackStackState(Handler handler, String name, int id, int flags) {
        if (mBackStack == null) {
            return false;
        }
        if (name == null && id < 0 && (flags&POP_BACK_STACK_INCLUSIVE) == 0) {
            int last = mBackStack.size()-1;
            if (last < 0) {
                return false;
            }
            final BackStackRecord bss = mBackStack.remove(last);
            SparseArray<Fragment> firstOutFragments = new SparseArray<Fragment>();
            SparseArray<Fragment> lastInFragments = new SparseArray<Fragment>();
            bss.calculateBackFragments(firstOutFragments, lastInFragments);
            bss.popFromBackStack(true, null, firstOutFragments, lastInFragments);
            reportBackStackChanged();
        } else {
           ...
        }
        return true;
    }

看一下这个方法,依据op.cmd执行相反的操作,我们的假设的是Fragment被remove后添加进回退栈,那么此时它的状态是CREATED,接着需要进行升级同步(按了回退键,立即同步到Activity的状态,见下面源码),那么它不会执行onAttach和onCreate回调,会直接执行onCreateView和onActivityCreated等回调 。

    //BackSatckRecord.java
    public TransitionState popFromBackStack(boolean doStateMove, TransitionState state,
            SparseArray<Fragment> firstOutFragments, SparseArray<Fragment> lastInFragments) {
        ...

        bumpBackStackNesting(-1);
        ....
        Op op = mTail;
        while (op != null) {
            int popEnterAnim = state != null ? 0 : op.popEnterAnim;
            int popExitAnim= state != null ? 0 : op.popExitAnim;
            switch (op.cmd) {
                ...
                case OP_REMOVE: {
                    Fragment f = op.fragment;
                    f.mNextAnim = popEnterAnim;
                    mManager.addFragment(f, false);
                } break;
                ...
                default: {
                    throw new IllegalArgumentException("Unknown cmd: " + op.cmd);
                }
            }

            op = op.prev;
        }
        //传入的是true,立刻同步所有Fragment的状态到Activity的状态
        if (doStateMove) {
            mManager.moveToState(mManager.mCurState,
                    FragmentManagerImpl.reverseTransit(transition), transitionStyle, true);
            state = null;
        }
        ...
        return state;
    }

setRetainInstance(true)的影响

这个方法也是简单地为一个变量赋值。

    //Fragment.java
    public void setRetainInstance(boolean retain) {
        if (retain && mParentFragment != null) {
            throw new IllegalStateException(
                    "Can't retain fragements that are nested in other fragments");
        }
        mRetainInstance = retain;
    }

在FragmentActivity因为配置变化而需要保存Fragment的状态的时候。

    //FragmentActivity.java
    public final Object onRetainNonConfigurationInstance() {
        ...

        List<Fragment> fragments = mFragments.retainNonConfig();
        ...
    }

最终调用的是FragmentManagerImpl的方法,可以看到,如果Fragment的mRetainInstance为true,则其mRetaining被置为true并被添加到一个List中(稍后返回给系统)。

    //FragmentManagerImpl.java
    ArrayList<Fragment> retainNonConfig() {
        ArrayList<Fragment> fragments = null;
        if (mActive != null) {
            for (int i=0; i<mActive.size(); i++) {
                Fragment f = mActive.get(i);
                if (f != null && f.mRetainInstance) {
                    if (fragments == null) {
                        fragments = new ArrayList<Fragment>();
                    }
                    fragments.add(f);
                    f.mRetaining = true;
                    f.mTargetIndex = f.mTarget != null ? f.mTarget.mIndex : -1;
                    if (DEBUG) Log.v(TAG, "retainNonConfig: keeping retained " + f);
                }
            }
        }
        return fragments;
    }

Fragment的mRetaining被置为true之后会对它的生命周期产生怎样的影响?首先在降级同步中,它不会回调onDestroy方法,也不会使自己的index失效。

    //FragmentManagerImpl.java
    void moveToState(Fragment f, int newState, int transit, int transitionStyle,
            boolean keepActive) {
        ...
                            if (!f.mRetaining) {
                                f.performDestroy();
                            } 
                                if (!f.mRetaining) {
                                    makeInactive(f);
                                } 
        ...
    }

然后在恢复Fragment状态的升级同步中,它不会回调onCreate方法。

    //FragmentManagerImpl.java
    void moveToState(Fragment f, int newState, int transit, int transitionStyle,
            boolean keepActive) {
        ...
                    if (!f.mRetaining) {
                        f.performCreate(f.mSavedFragmentState);
                    }
                    f.mRetaining = false;
        ...
    }

直接添加Fragment带来的问题

如果用户不自己处理配置的变化,在FragmentActivity被重建回调onCreate时,会利用FragmentManagerState的mActive重建Fragment,如果此时用户重写onCreate还添加了该Fragment,就会出现两个Fragment,所以要加入判断。

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(v);
    MyFragment myFragment = (MyFragment) getSupportFragmentManager().findFragmentByTag("MyFragmentTag");
    if ( myFragment == null ){
        myFragment = new BlankFragment();
        getSupportFragmentManager().beginTransaction().add(R.id.container, myFragment, "MyFragmentTag").commit();
    }
}

女票良心美代,只做正品的搬运工。如果你觉得这篇文章帮助到了你一点点,扫码支持一下吧^ ^


二维码
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,752评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,100评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,244评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,099评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,210评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,307评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,346评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,133评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,546评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,849评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,019评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,702评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,331评论 3 319
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,030评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,260评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,871评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,898评论 2 351

推荐阅读更多精彩内容