Fragment的管理(FragmentManager)

最近在開發(fā)過程中發(fā)現(xiàn)自己對Fragment的管理原理理解的很模糊,于是以Android-28為基礎(chǔ),對Fragment的管理做了一下簡單梳理,記錄在此,方便后面查閱则果。

本文主要弄清下面幾個(gè)問題:

  • Transation()到底做了什么事情
  • Replace()操作,Fragment到底是什么顯示出來的蓄坏。
  • popBackStack()上一個(gè)Fragment是如何恢復(fù)的董习。

一榔袋、事務(wù)Transation到底做了哪些事情

首先明確一點(diǎn):所有可以使用Fragment的Activity都是FragmentActivity的子類。因?yàn)橹挥性贔ragmentActivity中才有FragmentManager铡俐。而Fragment是由FragmentManager來管理的凰兑。

getFragmentManager()獲取到的FragmentManager支持原生的Fragment,

getSupportFragmentManager()支持的是v4包的Fragment审丘。

1.1 FragmentManagerImpl 是 FragmentManager的實(shí)現(xiàn)類

在FragmentAactivity這個(gè)類下面吏够,當(dāng)我們調(diào)用getSupportManager的時(shí)候

public class FragmentActivity extends BaseFragmentActivityJB implements
        ActivityCompat.OnRequestPermissionsResultCallback,
        ActivityCompatApi23.RequestPermissionsRequestCodeValidator {
    ···
final FragmentController mFragments = FragmentController.createController(new HostCallbacks());
    
    ···

    public FragmentManager getSupportFragmentManager() {
        return mFragments.getSupportFragmentManager();
    }
    ···
}

我們可以看到FragmentActivity里面有一個(gè)FragmentController,這個(gè)FragmentController定義了所有對Fragment的管理操作滩报,包括我們的Activity在onCreate锅知,onResume,onDestroy等各種生命周期或回調(diào)對Fragment的影響脓钾,都是由這個(gè)類來控制的售睹。

public class FragmentController {
    private final FragmentHostCallback<?> mHost;

    /**
     * Returns a {@link FragmentController}.
     */
    public static final FragmentController createController(FragmentHostCallback<?> callbacks) {
        return new FragmentController(callbacks);
    }

    /**
     * Returns a {@link FragmentManager} for this controller.
     */
    public FragmentManager getSupportFragmentManager() {
        //獲取到FragmentManager對象
        return mHost.getFragmentManagerImpl();
    }

FragmentHostCallback是一個(gè)抽象類,負(fù)責(zé)調(diào)用各種各樣的回調(diào)可训。
HostCallbacks是FragmentActivity里面的一個(gè)繼承FragmentHostCallback的內(nèi)部類昌妹。下面我們來看看FragmentHostCallback的默認(rèn)實(shí)現(xiàn)

public abstract class FragmentHostCallback<E> extends FragmentContainer {
    private final Activity mActivity;
    ···
    // 實(shí)例化FragmentManager對象,F(xiàn)ragmentManagerImpl是繼承自FragmentManager抽象類的握截,對FragmentManager的各種方法提供具體實(shí)現(xiàn)
    final FragmentManagerImpl mFragmentManager = new FragmentManagerImpl();
    ···
}

至此我們找到了Fragment的實(shí)現(xiàn)類FragmentManagerImpl

FragmentManagerImpl里面的具體實(shí)現(xiàn)就是有關(guān)Fragment是如何運(yùn)行的飞崖,各種各樣的生命周期弧圆,判斷Fragment的不同狀態(tài)昆庇,切換狀態(tài),Transaction只是用作記錄對Fragment的操作記錄砰逻,最終調(diào)用commit的時(shí)候畜眨,實(shí)際上調(diào)用的還是FragmentManagerImpl的方法

1.2、 FragmentTransaction 是操作Fragment的橋梁术瓮。

每次我們對Fragment進(jìn)行操作 都是通過FragmentTransaction這個(gè)類來實(shí)現(xiàn)康聂。

FragmentTransaction的一些常用使用方式:

//添加Fragment到FragmentList中
private void addFragment(Fragment fragment, String tag){
        FragmentManager fragmentManager = getSupportFragmentManager();
        FragmentTransaction transaction = fragmentManager.beginTransaction();
        transaction.add(R.id.fragment_container,fragment,tag);
        transaction.commit();
    }

// 清空fragmentList的所有Fragment,替換成新的Fragment胞四,注意Fragment里面的坑
private void replaceFragment(Fragment fragment, String tag){
        FragmentManager fragmentManager = getSupportFragmentManager();
        FragmentTransaction transaction = fragmentManager.beginTransaction();
        transaction.replace(R.id.fragment_container,fragment,tag);
        transaction.commit();
    }

//移除指定的Fragment
private void removeFragment(Fragment fragment){
        FragmentManager fragmentManager = getSupportFragmentManager();
        FragmentTransaction transaction = fragmentManager.beginTransaction();
        transaction.remove(fragment);
        transaction.commit();
    }

//把Fragment設(shè)置成顯示狀態(tài)恬汁,但是并沒有添加到FragmentList中
private void showFragment(Fragment fragment){
        FragmentManager fragmentManager = getSupportFragmentManager();
        FragmentTransaction transaction = fragmentManager.beginTransaction();
        transaction.show(fragment);
        transaction.commit();
    }

//把Fragment設(shè)置成顯示狀態(tài),但是并沒有添加到FragmentList中
private void hideFragment(Fragment fragment){
        FragmentManager fragmentManager = getSupportFragmentManager();
        FragmentTransaction transaction = fragmentManager.beginTransaction();
        transaction.hide(fragment);
        transaction.commit();
    }

// 效果和show相近辜伟,創(chuàng)建視圖氓侧,添加到containerid指定的Added列表,F(xiàn)ragmentList依然保留导狡,但是會(huì)引起生命周期的變化
private void attachFragment(Fragment fragment){
        FragmentManager fragmentManager = getSupportFragmentManager();
        FragmentTransaction transaction = fragmentManager.beginTransaction();
        transaction.attach(fragment);
        transaction.commit();
    }

// 效果和hide相近约巷,清除視圖,從containerid指定的Added列表移除旱捧,F(xiàn)ragmentList依然保留独郎,但是會(huì)引起生命周期的變化
private void detachFragment(Fragment fragment){
        FragmentManager fragmentManager = getSupportFragmentManager();
        FragmentTransaction transaction = fragmentManager.beginTransaction();
        transaction.detach(fragment);
        transaction.commit();
    }

核心敲重點(diǎn):

Transaction只是用作記錄對Fragment的操作記錄踩麦,最終調(diào)用commit的時(shí)候,實(shí)際上調(diào)用的還是FragmentManagerImpl的方法

FragmentManager.beginTransaction() 返回的是一個(gè)BackStackRecord的實(shí)例,而BackStackRecord繼承自FragmentTransaction

// FragmentManager 的實(shí)現(xiàn)類
final class FragmentManagerImpl extends FragmentManager implements LayoutInflaterFactory {
    ···
    @Override
    public FragmentTransaction beginTransaction() {
        // 每次的FragmentTransaction都是獨(dú)立的
        return new BackStackRecord(this);
    }
    ···
}

// Transaction的實(shí)現(xiàn)類
final class BackStackRecord extends FragmentTransaction implements
        FragmentManager.BackStackEntry, FragmentManagerImpl.OpGenerator {

    // 初始化的時(shí)候傳入FragmentManagerImpl 的實(shí)例
    public BackStackRecord(FragmentManagerImpl manager) {
        mManager = manager;
    }

    @Override
    public int commit() {
        //返回棧id氓癌,要是不添加進(jìn)棧谓谦,返回-1
        return commitInternal(false);
    }

    int commitInternal(boolean allowStateLoss) {
       // 提交以后無法再次提交
        if (mCommitted) throw new IllegalStateException("commit already called");
        if (FragmentManagerImpl.DEBUG) {
            Log.v(TAG, "Commit: " + this);
            LogWriter logw = new LogWriter(TAG);
            PrintWriter pw = new PrintWriter(logw);
            dump("  ", null, pw, null);
        }
        mCommitted = true;
        //是否要添加到回退棧
        if (mAddToBackStack) {
            // 在回退棧中分配棧ID
            mIndex = mManager.allocBackStackIndex(this);
        } else {
            mIndex = -1;
        }
        //執(zhí)行這個(gè)Transaction
        mManager.enqueueAction(this, allowStateLoss);
        return mIndex;
    }

}

FragmentTransaction 支持一系列的操作

#將一個(gè)fragment實(shí)例添加到Activity里面指定id的容器中
add(Fragment fragment, String tag)
add(int containerViewId, Fragment fragment)
add(int containerViewId, Fragment fragment, String tag);
 #將一個(gè)fragment實(shí)例從FragmentManager的FragmentList中移除
remove(Fragment fragment);
#只控制Fragment的隱藏
hide(Fragment fragment)
#只控制Fragment的顯示
show(Fragment fragment)
#清除視圖,從containerid指定的Added列表移除贪婉,F(xiàn)ragmentList依然保留
detach(Fragment fragment)
#創(chuàng)建視圖反粥,添加到containerid指定的Added列表,F(xiàn)ragmentList依然保留
attach(Fragment fragment)
#替換containerViewId中的fragment疲迂,它會(huì)把containerViewId中所有fragment刪除才顿,然后添加當(dāng)前的fragment
replace(int containerViewId, Fragment fragment)
replace(int containerViewId, Fragment fragment, String tag)

FragmentTransaction 其實(shí)就是一個(gè)容器,內(nèi)部維護(hù)一個(gè)mOps數(shù)組,執(zhí)行add(),remove(),replace()操作時(shí),所做的就是講這些操作封裝成Op對象保存在mOps數(shù)組中。

public abstract class FragmentTransaction {

    static final int OP_NULL = 0;
    static final int OP_ADD = 1;
    static final int OP_REPLACE = 2;
    static final int OP_REMOVE = 3;
    static final int OP_HIDE = 4;
    static final int OP_SHOW = 5;
    static final int OP_DETACH = 6;
    static final int OP_ATTACH = 7;
    static final int OP_SET_PRIMARY_NAV = 8;
    static final int OP_UNSET_PRIMARY_NAV = 9;
    static final int OP_SET_MAX_LIFECYCLE = 10;

 static final class Op {
        int mCmd;
        Fragment mFragment;


        Op() {
        }

        Op(int cmd, Fragment fragment) {
            this.mCmd = cmd;
            this.mFragment = fragment;
           
        }
}

    ArrayList<Op> mOps = new ArrayList<>();
    

    void addOp(Op op) {
        mOps.add(op);
        op.mEnterAnim = mEnterAnim;
        op.mExitAnim = mExitAnim;
        op.mPopEnterAnim = mPopEnterAnim;
        op.mPopExitAnim = mPopExitAnim;
    }

    /**
     * Calls {@link #add(int, Fragment, String)} with a 0 containerViewId.
     */
    @NonNull
    public FragmentTransaction add(@NonNull Fragment fragment, @Nullable String tag)  {
        doAddOp(0, fragment, tag, OP_ADD);
        return this;
    }

     @NonNull
    public FragmentTransaction remove(@NonNull Fragment fragment) {
        addOp(new Op(OP_REMOVE, fragment));

        return this;
    }
}

當(dāng)執(zhí)行FragmentTransaction.commit時(shí),最終會(huì)調(diào)用FragmentManager.enqueueAction(),將BackStackRecord加入到FragmentManager的一個(gè)執(zhí)行隊(duì)列中,這個(gè)操作隊(duì)列會(huì)在主線程中順序被執(zhí)行鬼譬。

final class BackStackRecord{
   @Override
    public int commit() {
        return commitInternal(false);
    }
    
    int commitInternal(boolean allowStateLoss) {
        if (mCommitted) throw new IllegalStateException("commit already called");
        if (FragmentManagerImpl.DEBUG) {
            Log.v(TAG, "Commit: " + this);
            LogWriter logw = new LogWriter(TAG);
            PrintWriter pw = new PrintWriter(logw);
            dump("  ", pw);
            pw.close();
        }
        mCommitted = true;
        if (mAddToBackStack) {
            mIndex = mManager.allocBackStackIndex(this);
        } else {
            mIndex = -1;
        }
        mManager.enqueueAction(this, allowStateLoss);
        return mIndex;
    }
}

二娜膘、BackStackRecord的執(zhí)行

BackStackRecord加入到FragmentManager隊(duì)列中是如何被執(zhí)行的,Fragment又是如何顯示出來的呢?(add操作)

FragmentManagerImpl類

  /**
     * Adds an action to the queue of pending actions.
     *
     * @param action the action to add
     * @param allowStateLoss whether to allow loss of state information
     * @throws IllegalStateException if the activity has been destroyed
     */
    public void enqueueAction(OpGenerator action, boolean allowStateLoss) {
        if (!allowStateLoss) {
            checkStateLoss();
        }
        synchronized (this) {
            if (mDestroyed || mHost == null) {
                if (allowStateLoss) {
                    // This FragmentManager isn't attached, so drop the entire transaction.
                    return;
                }
                throw new IllegalStateException("Activity has been destroyed");
            }
            if (mPendingActions == null) {
                mPendingActions = new ArrayList<>();
            }
            mPendingActions.add(action);
            scheduleCommit();
        }
    }
    

    
      void scheduleCommit() {
        synchronized (this) {
            boolean postponeReady =
                    mPostponedTransactions != null && !mPostponedTransactions.isEmpty();
            boolean pendingReady = mPendingActions != null && mPendingActions.size() == 1;
            if (postponeReady || pendingReady) {
                mHost.getHandler().removeCallbacks(mExecCommit);
                mHost.getHandler().post(mExecCommit);
                updateOnBackPressedCallbackEnabled();
            }
        }
    }
    
       Runnable mExecCommit = new Runnable() {
        @Override
        public void run() {
            execPendingActions();
        }
    };
    
      /**
     * Only call from main thread!
     */
    public boolean execPendingActions() {
        ensureExecReady(true);

        removeRedundantOperationsAndExecute(mTmpRecords, mTmpIsPop);
          
     
        return didSomething;
    }
    
    private void removeRedundantOperationsAndExecute(ArrayList<BackStackRecord> records,ArrayList<Boolean> isRecordPop) {
                   executeOpsTogether(records, isRecordPop, recordNum, reorderingEnd);                          
        
    }
    
      private void executeOpsTogether(ArrayList<BackStackRecord> records,
                                    ArrayList<Boolean> isRecordPop, int startIndex, int endIndex) {
        final boolean allowReordering = records.get(startIndex).mReorderingAllowed;
        boolean addToBackStack = false;
        if (mTmpAddedFragments == null) {
            mTmpAddedFragments = new ArrayList<>();
        } else {
            mTmpAddedFragments.clear();
        }
        mTmpAddedFragments.addAll(mAdded);
        Fragment oldPrimaryNav = getPrimaryNavigationFragment();
        for (int recordNum = startIndex; recordNum < endIndex; recordNum++) {
            final BackStackRecord record = records.get(recordNum);
            final boolean isPop = isRecordPop.get(recordNum);
            if (!isPop) {
            
                //注釋一:將ops操作 拆解為基本操作的序列
                oldPrimaryNav = record.expandOps(mTmpAddedFragments, oldPrimaryNav);
            } else {
                oldPrimaryNav = record.trackAddedFragmentsInPop(mTmpAddedFragments, oldPrimaryNav);
            }
            addToBackStack = addToBackStack || record.mAddToBackStack;
        }
        mTmpAddedFragments.clear();

 
        executeOps(records, isRecordPop, startIndex, endIndex);

    
    }
    
    private static void executeOps(ArrayList<BackStackRecord> records,
                               ArrayList<Boolean> isRecordPop, int startIndex, int endIndex) {
    for (int i = startIndex; i < endIndex; i++) {
        final BackStackRecord record = records.get(i);
        final boolean isPop = isRecordPop.get(i);
        if (isPop) {
            record.bumpBackStackNesting(-1);
       
            boolean moveToState = i == (endIndex - 1);
            //注釋二:出棧操作,執(zhí)行executePopOps
            record.executePopOps(moveToState);
        } else {
            record.bumpBackStackNesting(1);
            //注釋三:入棧操作,執(zhí)行executeOps()
            record.executeOps();
        }
    }
}


  • 注釋一:record.expandOps()會(huì)將ops操作 拆解為更簡單的基本操作序列,如replace()操作,會(huì)被拆解為N個(gè)Remove+1個(gè)Add操作优质,保存在mOps數(shù)組中竣贪。
  • 注釋二:如果當(dāng)前BackStackRecord是出棧操作,則執(zhí)行record.executePopOps()
  • 注釋三:如果當(dāng)前BackStackRecord是入棧操作,則執(zhí)行record.executeOps()

下面我們重點(diǎn)看一下BackStackRecord的這三個(gè)方法

2.1、 BackStackRecord.expandOps():

expandOps的主要作用擴(kuò)展Op操作,將原始是Ops操作擴(kuò)展成更基本的Ops序列,它會(huì)修改FragmentManagetImpl的mAdded數(shù)組和oldPrimaryNav

  /**
     * Expands all meta-ops into their more primitive equivalents. This must be called prior to
     * {@link #executeOps()} or any other call that operations on mOps for forward navigation.
     * It should not be called for pop/reverse navigation operations.
     *
     * <p>Removes all OP_REPLACE ops and replaces them with the proper add and remove
     * operations that are equivalent to the replace.</p>
     *
     * <p>Adds OP_UNSET_PRIMARY_NAV ops to match OP_SET_PRIMARY_NAV, OP_REMOVE and OP_DETACH
     * ops so that we can restore the old primary nav fragment later. Since callers call this
     * method in a loop before running ops from several transactions at once, the caller should
     * pass the return value from this method as the oldPrimaryNav parameter for the next call.
     * The first call in such a loop should pass the value of
     * {@link FragmentManager#getPrimaryNavigationFragment()}.</p>
     *
     * @param added Initialized to the fragments that are in the mManager.mAdded, this
     *              will be modified to contain the fragments that will be in mAdded
     *              after the execution ({@link #executeOps()}.
     * @param oldPrimaryNav The tracked primary navigation fragment as of the beginning of
     *                      this set of ops
     * @return the new oldPrimaryNav fragment after this record's ops would be run
     */
    @SuppressWarnings("ReferenceEquality")
    Fragment expandOps(ArrayList<Fragment> added, Fragment oldPrimaryNav) {
        for (int opNum = 0; opNum < mOps.size(); opNum++) {
            final Op op = mOps.get(opNum);
            switch (op.mCmd) {
                
                case OP_ADD:
                case OP_ATTACH:
                    //(1)ADD和ATTACH方法,僅將mFragment添加到mAdded數(shù)組
                    added.add(op.mFragment);
                    break;
                case OP_REMOVE:
                case OP_DETACH: {
                    //(2)REMOVE和DETACH操作,將mFragment從added數(shù)組移除,并插入OP_UNSET_PRIMARY_NAV操作,將oldPrimaryNav移除
                    added.remove(op.mFragment);
                    if (op.mFragment == oldPrimaryNav) {
                        mOps.add(opNum, new Op(OP_UNSET_PRIMARY_NAV, op.mFragment));
                        opNum++;
                        oldPrimaryNav = null;
                    }
                }
                break;
                case OP_REPLACE: {
                    //(3)REPLACE 將added數(shù)組中,所有mContainerId匹配的Frament移除,然后再j將當(dāng)前Frament添加巩螃。replace操作 轉(zhuǎn)變成了REMOVE*N+ADD的序列
                    final Fragment f = op.mFragment;
                    final int containerId = f.mContainerId;
                    boolean alreadyAdded = false;
                    for (int i = added.size() - 1; i >= 0; i--) {
                        final Fragment old = added.get(i);
                        if (old.mContainerId == containerId) {
                            if (old == f) {
                                alreadyAdded = true;
                            } else {
                                // This is duplicated from above since we only make
                                // a single pass for expanding ops. Unset any outgoing primary nav.
                                if (old == oldPrimaryNav) {
                                    mOps.add(opNum, new Op(OP_UNSET_PRIMARY_NAV, old));
                                    opNum++;
                                    oldPrimaryNav = null;
                                }
                                final Op removeOp = new Op(OP_REMOVE, old);
                                removeOp.mEnterAnim = op.mEnterAnim;
                                removeOp.mPopEnterAnim = op.mPopEnterAnim;
                                removeOp.mExitAnim = op.mExitAnim;
                                removeOp.mPopExitAnim = op.mPopExitAnim;
                                mOps.add(opNum, removeOp);
                                added.remove(old);
                                opNum++;
                            }
                        }
                    }
                    if (alreadyAdded) {
                        mOps.remove(opNum);
                        opNum--;
                    } else {
                        op.mCmd = OP_ADD;
                        added.add(f);
                    }
                }
                break;
                //(4)SET_PRIMARY_NAV 操作,更新oldPrimaryNav的值
                case OP_SET_PRIMARY_NAV: {
                    // It's ok if this is null, that means we will restore to no active
                    // primary navigation fragment on a pop.
                    mOps.add(opNum, new Op(OP_UNSET_PRIMARY_NAV, oldPrimaryNav));
                    opNum++;
                    // Will be set by the OP_SET_PRIMARY_NAV we inserted before when run
                    oldPrimaryNav = op.mFragment;
                }
                break;
            }
        }
        return oldPrimaryNav;
    }
  • (1)ADD和ATTACH方法,僅將mFragment添加到mAdded數(shù)組
  • (2)REMOVE和DETACH操作,將mFragment從added數(shù)組移除,并插入OP_UNSET_PRIMARY_NAV操作,將oldPrimaryNav移除演怎。
  • (3)REPLACE 將added數(shù)組中,所有mContainerId匹配的Frament移除,然后再j將當(dāng)前Frament添加。replace操作 轉(zhuǎn)變成了REMOVE*N+ADD的序列避乏。
  • (4)SET_PRIMARY_NAV 操作,更新oldPrimaryNav的值

2.2爷耀、 BackStackRecord.executeOps() 入棧操作

當(dāng)Fragment入棧時(shí),會(huì)執(zhí)行BackStackRecord.executeOps()方法
executeOps方法中,將Op操作 都代理到了FragmentManagerImpl對應(yīng)的方法。

    void executeOps() {
        final int numOps = mOps.size();
        for (int opNum = 0; opNum < numOps; opNum++) {
            final Op op = mOps.get(opNum);
            final Fragment f = op.mFragment;
            if (f != null) {
                f.setNextTransition(mTransition, mTransitionStyle);
            }
            switch (op.mCmd) {
                case OP_ADD:
                    f.setNextAnim(op.mEnterAnim);
                    mManager.addFragment(f, false);
                    break;
                case OP_REMOVE:
                    f.setNextAnim(op.mExitAnim);
                    mManager.removeFragment(f);
                    break;
                case OP_HIDE:
                    f.setNextAnim(op.mExitAnim);
                    mManager.hideFragment(f);
                    break;
                case OP_SHOW:
                    f.setNextAnim(op.mEnterAnim);
                    mManager.showFragment(f);
                    break;
                case OP_DETACH:
                    f.setNextAnim(op.mExitAnim);
                    mManager.detachFragment(f);
                    break;
                case OP_ATTACH:
                    f.setNextAnim(op.mEnterAnim);
                    mManager.attachFragment(f);
                    break;
                case OP_SET_PRIMARY_NAV:
                    mManager.setPrimaryNavigationFragment(f);
                    break;
                case OP_UNSET_PRIMARY_NAV:
                    mManager.setPrimaryNavigationFragment(null);
                    break;
                case OP_SET_MAX_LIFECYCLE:
                    mManager.setMaxLifecycle(f, op.mCurrentMaxState);
                    break;
                default:
                    throw new IllegalArgumentException("Unknown cmd: " + op.mCmd);
            }
            if (!mReorderingAllowed && op.mCmd != OP_ADD && f != null) {
                mManager.moveFragmentToExpectedState(f);
            }
        }
        if (!mReorderingAllowed) {
            // Added fragments are added at the end to comply with prior behavior.
            mManager.moveToState(mManager.mCurState, true);
        }
    }

執(zhí)行OP_ADD時(shí) 會(huì)順序執(zhí)行

  • FragmentManagerImpl.addFragment()
  • FragmentManagerImpl.moveToState()
  • FragmentManagerImpl.moveFragmentToExpectedState()
  • FragmentManagerImpl.moveToState(Fragment f, int newState, int transit, int transitionStyle, boolean keepActive)

addFragment中的核心操作 就是將將Fragmet加入到mAdded數(shù)組,同時(shí)修改Fragment對應(yīng)的標(biāo)志位

  public void addFragment(Fragment fragment, boolean moveToStateNow) {
        if (DEBUG) Log.v(TAG, "add: " + fragment);
        makeActive(fragment);
        if (!fragment.mDetached) {
            //將Fragmet加入到mAdded數(shù)組
            synchronized (mAdded) {
                mAdded.add(fragment);
            }
            //修改frament中的標(biāo)志位
            fragment.mAdded = true;
            fragment.mRemoving = false;
         
            if (moveToStateNow) {
                moveToState(fragment);
            }
        }
    }

操作二:調(diào)用moveToState()方法
moveFragmentToExpectedState->moveToState()

2.3拍皮、 FragmentManagerImpl.moveToState() 執(zhí)行Fragment的狀態(tài)切換

void moveToState(Fragment f, int newState, int transit, int transitionStyle,
                     boolean keepActive) {
        // Fragments that are not currently added will sit in the onCreate() state.
        if ((!f.mAdded || f.mDetached) && newState > Fragment.CREATED) {
            newState = Fragment.CREATED;
        }
 
       
        // Don't allow the Fragment to go above its max lifecycle state
        // Ensure that Fragments are capped at CREATED instead of ACTIVITY_CREATED.
        if (f.mMaxState == Lifecycle.State.CREATED) {
            newState = Math.min(newState, Fragment.CREATED);
        } else {
            newState = Math.min(newState, f.mMaxState.ordinal());

        }

        //如果newState > Fragment當(dāng)前的狀態(tài)
        if (f.mState <= newState) {
          
          
            switch (f.mState) {
                case Fragment.INITIALIZING:
                    if (newState > Fragment.INITIALIZING) {
                        if (DEBUG) Log.v(TAG, "moveto CREATED: " + f);
             

                        f.mHost = mHost;
                        f.mParentFragment = mParent;
                        f.mFragmentManager = mParent != null
                                ? mParent.mChildFragmentManager : mHost.mFragmentManager;

                        //(1)執(zhí)行Fragment.attach()
                        f.performAttach();
                        if (f.mParentFragment == null) {
                            mHost.onAttachFragment(f);
                        } else {
                            f.mParentFragment.onAttachFragment(f);
                        }
               
                        //(2)執(zhí)行Fragmet.onCreate()
                        if (!f.mIsCreated) {
                            dispatchOnFragmentPreCreated(f, f.mSavedFragmentState, false);
                            f.performCreate(f.mSavedFragmentState);
                            dispatchOnFragmentCreated(f, f.mSavedFragmentState, false);
                        } else {
                            f.restoreChildFragmentState(f.mSavedFragmentState);
                            f.mState = Fragment.CREATED;
                        }
                    }
                    // fall through
                case Fragment.CREATED:
                 

                    if (newState > Fragment.CREATED) {
                      
                        if (!f.mFromLayout) {
                            ViewGroup container = null;
                            if (f.mContainerId != 0) {
                                
                            //(1)提取Fragment的ContainerId 對應(yīng)的ViewGroup
                            container = (ViewGroup) mContainer.onFindViewById(f.mContainerId);
                     
                            // (2) 調(diào)用Fragment的onCreateView()繪制Fragment中的View
                            f.mContainer = container;
                            f.performCreateView(f.performGetLayoutInflater(
                                    f.mSavedFragmentState), container, f.mSavedFragmentState);
                            if (f.mView != null) {
                                f.mInnerView = f.mView;
                                f.mView.setSaveFromParentEnabled(false);
                                //(3)將Framgnet中的View 添加到ContrainerView當(dāng)中
                                if (container != null) {
                                    container.addView(f.mView);
                                }
                                if (f.mHidden) {
                                    f.mView.setVisibility(View.GONE);
                                }
                                //(4)調(diào)用Fragment的OnViewCreated() 
                                f.onViewCreated(f.mView, f.mSavedFragmentState);
                                dispatchOnFragmentViewCreated(f, f.mView, f.mSavedFragmentState,
                                        false);
                    
                                f.mIsNewlyAdded = (f.mView.getVisibility() == View.VISIBLE)
                                        && f.mContainer != null;
                            } else {
                                f.mInnerView = null;
                            }
                        }
                        //(5)調(diào)用Fragment的onActivityCreated() 
                        f.performActivityCreated(f.mSavedFragmentState);
                        dispatchOnFragmentActivityCreated(f, f.mSavedFragmentState, false);
                        if (f.mView != null) {
                            f.restoreViewState(f.mSavedFragmentState);
                        }
                        f.mSavedFragmentState = null;
                    }
                    // fall through
                case Fragment.ACTIVITY_CREATED:
                    //(1) 調(diào)用Fragment.onStart()
                    if (newState > Fragment.ACTIVITY_CREATED) {
                        if (DEBUG) Log.v(TAG, "moveto STARTED: " + f);
                        f.performStart();
                        dispatchOnFragmentStarted(f, false);
                    }
                    // fall through
                case Fragment.STARTED:
                         //(1) 調(diào)用Fragment.onResume() 
                    if (newState > Fragment.STARTED) {
                        if (DEBUG) Log.v(TAG, "moveto RESUMED: " + f);
                        f.performResume();
                        dispatchOnFragmentResumed(f, false);
                        f.mSavedFragmentState = null;
                        f.mSavedViewState = null;
                    }
            }
        } else if (f.mState > newState) {
          ... //執(zhí)行一些列反向的操作 
           switch (f.mState) {
                case Fragment.RESUMED:
                    if (newState < Fragment.RESUMED) {
                        if (DEBUG) Log.v(TAG, "movefrom RESUMED: " + f);
                        f.performPause();
                        dispatchOnFragmentPaused(f, false);
                    }
                    // fall through
                case Fragment.STARTED:
                    if (newState < Fragment.STARTED) {
                        if (DEBUG) Log.v(TAG, "movefrom STARTED: " + f);
                        f.performStop();
                        dispatchOnFragmentStopped(f, false);
                    }
                    // fall through
                }
        
        }

        if (f.mState != newState) {
          
            f.mState = newState;
        }
    }

Fragment 有以下幾個(gè)狀態(tài):

    static final int INITIALIZING = 0;     // Not yet created.
    static final int CREATED = 1;          // Created.
    static final int ACTIVITY_CREATED = 2; // Fully created, not started.
    static final int STARTED = 3;          // Created and started, not resumed.
    static final int RESUMED = 4;          // Created started and resumed.

moveToState()方法 將Fragment由當(dāng)前的mState狀態(tài)切換為newState狀態(tài)歹叮。
當(dāng)newState>Fragment.mState 進(jìn)行Fraggment的正向生命周期,當(dāng)newState<Fragment.state,執(zhí)行Fragment的逆向生命周期。

以正向聲明周期為例,

  • Fragment.state == INITIALIZING: 表示Not yet created, 執(zhí)行操作
Fragment.onCreate()
Fragment.onAttach()
  • Fragment.state == CREATED: 表示 Created,執(zhí)行操作
(1) 提取Fragment的ContainerId 對應(yīng)的ViewGroup

(2) 調(diào)用Fragment的onCreateView()獲取Fragment中的的View

(3) 將Framgnet中的View 添加到ContrainerView當(dāng)中

(4) 調(diào)用Fragment的OnViewCreated() 

(5) 調(diào)用Fragment的onActivityCreated() 
  • Fragment.state == ACTIVITY_CREATED:表示Fully created, not started铆帽,執(zhí)行操作
Fragment.onStart()
  • Fragment.state == STARTED ,表示 Created started and resumed.

2.4咆耿、BackStackRecord.executePopOps()

executePopOps()是Fragment出棧時(shí)的操作,是入棧操作的逆操作。

 void executePopOps(boolean moveToState) {
        for (int opNum = mOps.size() - 1; opNum >= 0; opNum--) {
            final Op op = mOps.get(opNum);
            Fragment f = op.mFragment;
            if (f != null) {
                f.setNextTransition(FragmentManagerImpl.reverseTransit(mTransition),
                        mTransitionStyle);
            }
            switch (op.mCmd) {
                case OP_ADD:
                    f.setNextAnim(op.mPopExitAnim);
                    mManager.removeFragment(f);
                    break;
                case OP_REMOVE:
                    f.setNextAnim(op.mPopEnterAnim);
                    mManager.addFragment(f, false);
                    break;
                case OP_HIDE:
                    f.setNextAnim(op.mPopEnterAnim);
                    mManager.showFragment(f);
                    break;
                case OP_SHOW:
                    f.setNextAnim(op.mPopExitAnim);
                    mManager.hideFragment(f);
                    break;
                case OP_DETACH:
                    f.setNextAnim(op.mPopEnterAnim);
                    mManager.attachFragment(f);
                    break;
                case OP_ATTACH:
                    f.setNextAnim(op.mPopExitAnim);
                    mManager.detachFragment(f);
                    break;
                case OP_SET_PRIMARY_NAV:
                    mManager.setPrimaryNavigationFragment(null);
                    break;
                case OP_UNSET_PRIMARY_NAV:
                    mManager.setPrimaryNavigationFragment(f);
                    break;
                case OP_SET_MAX_LIFECYCLE:
                    mManager.setMaxLifecycle(f, op.mOldMaxState);
                    break;
                default:
                    throw new IllegalArgumentException("Unknown cmd: " + op.mCmd);
            }
            if (!mReorderingAllowed && op.mCmd != OP_REMOVE && f != null) {
                mManager.moveFragmentToExpectedState(f);
            }
        }
        if (!mReorderingAllowed && moveToState) {
            mManager.moveToState(mManager.mCurState, true);
        }
    }

2.5爹橱、總結(jié)一下執(zhí)行replace()時(shí) Fragment的View是如何顯示出來的

假設(shè)Actvity中當(dāng)前正在顯示FragmentA,此時(shí)在同一個(gè)ContainerID上執(zhí)行replace(FragmentB())萨螺。執(zhí)行過程如下:

  • BackStackRecord.expendOp()方法將OP_REPLACE 操作被拆分 一個(gè)OP_REMOVE和一個(gè)OP_ADD操作
  • 執(zhí)行 BackStackRecord.executeOps()
- FragmentA執(zhí)行OP_REMOVE 被移除
- FragmentB執(zhí)行OP_ADD 被添加 
  • FragmentManagerImpl.moveToState()
當(dāng)Fragment.mState == CREATED 時(shí),執(zhí)行一下操作
(1) 提取Fragment的ContainerId 對應(yīng)的ViewGroup

(2) 調(diào)用Fragment的onCreateView()獲取Fragment中的的View

(3) 將Framgnet中的View 添加到ContrainerView當(dāng)中

(4) 調(diào)用Fragment的OnViewCreated() 

(5) 調(diào)用Fragment的onActivityCreated() 

至此FragmentB 被添加到Activity的View樹中,顯示出來。

三愧驱、Fragment是如何回退的慰技。

FragmentManager中有一個(gè)mBackStack數(shù)組,承載了加入回退棧中的FragmentTransaction操作

final class FragmentManagerImpl extends FragmentManager implements LayoutInflater.Factory2

 ArrayList<BackStackRecord> mBackStack;//這個(gè)就是保存調(diào)用了addToBackStack方法的FragementTransaction,你看就是這個(gè)東西記錄了,你commit的操作 所以當(dāng)你調(diào)用了addToBackStack 以后再按返回鍵 就可以回到上一個(gè)fragment了
 
}

調(diào)用FragmentTransaction.addToBackStack()组砚,便將自己加入到回退棧中吻商。

 @NonNull
    public FragmentTransaction addToBackStack(@Nullable 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;
    }

當(dāng)點(diǎn)擊Android的回退鍵時(shí),會(huì)調(diào)用Activity的onBackPressed()方法。最終調(diào)用fragmentManager.popBackStackImmediate()方法糟红。

    public void onBackPressed() {
        if (mActionBar != null && mActionBar.collapseActionView()) {
            return;
        }

        FragmentManager fragmentManager = mFragments.getFragmentManager();

        if (fragmentManager.isStateSaved() || !fragmentManager.popBackStackImmediate()) {
            finishAfterTransition();
        }
    }
private boolean popBackStackImmediate(String name, int id, int flags) {
        //(1)popBackStackState 負(fù)責(zé)遍歷mBackStack回退棧,將回退棧中的操作整理填充到this.mTmpRecords,并記錄是否是pop回退操作(保留在this.mTmpIsPop)中
        boolean executePop = this.popBackStackState(this.mTmpRecords, this.mTmpIsPop, name, id, flags);
        if (executePop) {
            this.mExecutingActions = true;

            try {
            //(2) 根據(jù)this.mTmpRecords和this.mTmpIsPop 執(zhí)行具體的transantion
                this.removeRedundantOperationsAndExecute(this.mTmpRecords, this.mTmpIsPop);
            } finally {
                this.cleanupExec();
            }
        }

        this.doPendingDeferredStart();
        this.burpActive();
        return executePop;
    }

最終會(huì)調(diào)用到executeOps()方法手报,因?yàn)槭腔赝瞬僮?isRecordPop == true,會(huì)執(zhí)行record.executePopOps(moveToState);

    private static void executeOps(ArrayList<BackStackRecord> records, ArrayList<Boolean> isRecordPop, int startIndex, int endIndex) {
        for(int i = startIndex; i < endIndex; ++i) {
            BackStackRecord record = (BackStackRecord)records.get(i);
            boolean isPop = (Boolean)isRecordPop.get(i);
            if (isPop) {
                record.bumpBackStackNesting(-1);
                boolean moveToState = i == endIndex - 1;
                record.executePopOps(moveToState);
            } else {
                record.bumpBackStackNesting(1);
                record.executeOps();
            }
        }

    }

executePopOps()執(zhí)行原transaction操作的反向操作,如原操作是OP_ADD操作,則實(shí)際執(zhí)行OP_REMOVE操作;操作是OP_REMOVE操作蚯舱,則執(zhí)行OP_ADD操作。

  void executePopOps(boolean moveToState) {
        for (int opNum = mOps.size() - 1; opNum >= 0; opNum--) {
            final Op op = mOps.get(opNum);
            Fragment f = op.mFragment;
            if (f != null) {
                f.setNextTransition(FragmentManagerImpl.reverseTransit(mTransition),
                        mTransitionStyle);
            }
            switch (op.mCmd) {
                case OP_ADD:
                    f.setNextAnim(op.mPopExitAnim);
                    mManager.removeFragment(f);
                    break;
                case OP_REMOVE:
                    f.setNextAnim(op.mPopEnterAnim);
                    mManager.addFragment(f, false);
                    break;
                case OP_HIDE:
                    f.setNextAnim(op.mPopEnterAnim);
                    mManager.showFragment(f);
                    break;
                case OP_SHOW:
                    f.setNextAnim(op.mPopExitAnim);
                    mManager.hideFragment(f);
                    break;
                case OP_DETACH:
                    f.setNextAnim(op.mPopEnterAnim);
                    mManager.attachFragment(f);
                    break;
                case OP_ATTACH:
                    f.setNextAnim(op.mPopExitAnim);
                    mManager.detachFragment(f);
                    break;
                case OP_SET_PRIMARY_NAV:
                    mManager.setPrimaryNavigationFragment(null);
                    break;
                case OP_UNSET_PRIMARY_NAV:
                    mManager.setPrimaryNavigationFragment(f);
                    break;
                case OP_SET_MAX_LIFECYCLE:
                    mManager.setMaxLifecycle(f, op.mOldMaxState);
                    break;
                default:
                    throw new IllegalArgumentException("Unknown cmd: " + op.mCmd);
            }
            if (!mReorderingAllowed && op.mCmd != OP_REMOVE && f != null) {
                mManager.moveFragmentToExpectedState(f);
            }
        }
        if (!mReorderingAllowed && moveToState) {
            mManager.moveToState(mManager.mCurState, true);
        }
    }

注意:FragmenetTransantion.replace()操作,執(zhí)行時(shí)會(huì)被拆分成remove+add操作;相應(yīng)的,回退時(shí),順序執(zhí)行執(zhí)行remove和add操作掩蛤。

四枉昏、參考文章:

http://www.reibang.com/p/1ee67d935757
https://www.cnblogs.com/punkisnotdead/p/4974527.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市揍鸟,隨后出現(xiàn)的幾起案子兄裂,更是在濱河造成了極大的恐慌,老刑警劉巖阳藻,帶你破解...
    沈念sama閱讀 222,183評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件晰奖,死亡現(xiàn)場離奇詭異,居然都是意外死亡腥泥,警方通過查閱死者的電腦和手機(jī)匾南,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,850評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蛔外,“玉大人蛆楞,你說我怎么就攤上這事〖醒幔” “怎么了豹爹?”我有些...
    開封第一講書人閱讀 168,766評(píng)論 0 361
  • 文/不壞的土叔 我叫張陵,是天一觀的道長矛纹。 經(jīng)常有香客問我臂聋,道長,這世上最難降的妖魔是什么或南? 我笑而不...
    開封第一講書人閱讀 59,854評(píng)論 1 299
  • 正文 為了忘掉前任孩等,我火速辦了婚禮,結(jié)果婚禮上采够,老公的妹妹穿的比我還像新娘肄方。我一直安慰自己,他們只是感情好吁恍,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,871評(píng)論 6 398
  • 文/花漫 我一把揭開白布扒秸。 她就那樣靜靜地躺著播演,像睡著了一般冀瓦。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上写烤,一...
    開封第一講書人閱讀 52,457評(píng)論 1 311
  • 那天翼闽,我揣著相機(jī)與錄音,去河邊找鬼洲炊。 笑死感局,一個(gè)胖子當(dāng)著我的面吹牛尼啡,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播询微,決...
    沈念sama閱讀 40,999評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼崖瞭,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了撑毛?” 一聲冷哼從身側(cè)響起书聚,我...
    開封第一講書人閱讀 39,914評(píng)論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎藻雌,沒想到半個(gè)月后雌续,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,465評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡胯杭,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,543評(píng)論 3 342
  • 正文 我和宋清朗相戀三年驯杜,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片做个。...
    茶點(diǎn)故事閱讀 40,675評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡鸽心,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出叁温,到底是詐尸還是另有隱情再悼,我是刑警寧澤,帶...
    沈念sama閱讀 36,354評(píng)論 5 351
  • 正文 年R本政府宣布膝但,位于F島的核電站冲九,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏跟束。R本人自食惡果不足惜莺奸,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,029評(píng)論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望冀宴。 院中可真熱鬧灭贷,春花似錦、人聲如沸略贮。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,514評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽逃延。三九已至览妖,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間揽祥,已是汗流浹背讽膏。 一陣腳步聲響...
    開封第一講書人閱讀 33,616評(píng)論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留拄丰,地道東北人府树。 一個(gè)月前我還...
    沈念sama閱讀 49,091評(píng)論 3 378
  • 正文 我出身青樓俐末,卻偏偏與公主長得像,于是被迫代替她去往敵國和親奄侠。 傳聞我的和親對象是個(gè)殘疾皇子卓箫,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,685評(píng)論 2 360

推薦閱讀更多精彩內(nèi)容