Android-Fragment事務(wù)管理原理分析

一窝爪、Fragment事務(wù)提交的部分操作

1.相關(guān)源碼概念

FragmetActivity的getSupportFragmentManager()內(nèi)部是通過FragmentController.getSupportFragmentManager嘉冒,而FragmentController的內(nèi)部是獲取的HostCallbacks對象中的FragmentManager對象象对,這個對象在最新版本的Androidx源碼中误证,雖然是FragmentManagerImpl對象,但是FragmentManagerImpl其實是一個空子類威鹿。
通過FragmentManager.beginTransaction()獲取FragmentTransaction對象钾怔,而FragmentManager.beginTransaction()中的方法實現(xiàn)如下:

    public FragmentTransaction beginTransaction() {
        return new BackStackRecord(this);
    }

FragmentTransaction.add
FragmentTransaction.remove
FragmentTransaction.replace
FragmentTransaction.hide
FragmentTransaction.show
FragmentTransaction.setPrimaryNavigationFragment
FragmentTransaction.addToBackStack
FragmentTransaction.commit
FragmentTransaction的實現(xiàn)類只有一個BackStackRecord
其實這些所有的add、replace等境输,最終都是將Fragment的狀態(tài)變成了ADD蔗牡,然后最終在執(zhí)行的時候,都是通過調(diào)用FragmentManager.moveToState方法嗅剖,createView辩越,一直開始執(zhí)行生命周期,而在FragmentManager.moveToState方法中信粮,每個生命周期執(zhí)行完成之后黔攒,都會繼續(xù)調(diào)用moveToState轉(zhuǎn)成下一個步驟的生命周期狀態(tài)。
使用事務(wù)强缘,是為了保證連續(xù)的操作是原子性的督惰。
調(diào)用hide和show的時候,其實并不會去走生命周期旅掂。

2.FragmentActivity#getSupportFragmentManager()

該源碼邏輯在在上面已經(jīng)說了赏胚,這里就貼下源碼:

    // FragmentActivity.java
    public FragmentManager getSupportFragmentManager() {
        // 這里的mFragments其實就是FragmentController對象
        return mFragments.getSupportFragmentManager();
    }
    // FragmentController.java
    public FragmentManager getSupportFragmentManager() {
        // 獲取HostCallbacks對象中創(chuàng)建的FragmentManager對象
        return mHost.mFragmentManager;
    }
// FragmentHostCallback.java   這是HostCallbacks的父類,泛型是傳入的FragmentActivity
final FragmentManager mFragmentManager = new FragmentManagerImpl();

3.FragmentManager#beginTransaction

    // 獲取事務(wù)類商虐,BackStackRecord其實就是FragmentTransaction的子類實現(xiàn)
    public FragmentTransaction beginTransaction() {
        return new BackStackRecord(this);
    }
// 從BackStackRecord的源碼可以看出觉阅,BackStackRecord實現(xiàn)了FragmentTransaction抽象類
// 還實現(xiàn)了FragmentManager.OpGenerator接口,所以在這個流程中秘车,保存事務(wù)的時候典勇,可能會以FragmentManager.OpGenerator對象
// 也可能會以BackStackRecord保存,這是同一個叮趴。
final class BackStackRecord extends FragmentTransaction implements
        FragmentManager.BackStackEntry, FragmentManager.OpGenerator {

4.FragmentTransaction#add

(1)直接傳入Fragment的Class對象割笙,在內(nèi)部創(chuàng)建Fragment
    public final FragmentTransaction add(@NonNull Class<? extends Fragment> fragmentClass,
            @Nullable Bundle args, @Nullable String tag)  {
        return add(createFragment(fragmentClass, args), tag);
    }
    public FragmentTransaction add(@NonNull Fragment fragment, @Nullable String tag)  {
        // 調(diào)用add方法,設(shè)置Op的mCmd指令為OP_ADD
        doAddOp(0, fragment, tag, OP_ADD);
        return this;
    }
(2)傳入布局控件id和Fragment對象
    public final FragmentTransaction add(@IdRes int containerViewId,
            @NonNull Class<? extends Fragment> fragmentClass, @Nullable Bundle args)  {
        return add(containerViewId, createFragment(fragmentClass, args));
    }
    public FragmentTransaction add(@IdRes int containerViewId, @NonNull Fragment fragment) {
        doAddOp(containerViewId, fragment, null, OP_ADD);
        return this;
    }

5.FragmentTransaction#doAddOp

如果傳入的是Fragment的Class對象眯亦,這doAddOp操作的第一個參數(shù)直接傳0伤溉,如果是傳入具體的containerViewId豪嚎,則使用具體的containerViewId

    // 這步的主要操作就是設(shè)置tag和containerId
    void doAddOp(int containerViewId, Fragment fragment, @Nullable String tag, int opcmd) {
        final Class<?> fragmentClass = fragment.getClass();
        final int modifiers = fragmentClass.getModifiers();
        if (fragmentClass.isAnonymousClass() || !Modifier.isPublic(modifiers)
                || (fragmentClass.isMemberClass() && !Modifier.isStatic(modifiers))) {
            throw new IllegalStateException("Fragment " + fragmentClass.getCanonicalName()
                    + " must be a public static class to be  properly recreated from"
                    + " instance state.");
        }

        if (tag != null) {
            if (fragment.mTag != null && !tag.equals(fragment.mTag)) {
                throw new IllegalStateException("Can't change tag of fragment "
                        + fragment + ": was " + fragment.mTag
                        + " now " + tag);
            }
            fragment.mTag = tag;
        }
        // 判斷布局id是否為0,如果不為0谈火,設(shè)置給fragment對象的mContainerId值
        // 這是用于在fragment對象進行createView的時候使用
        if (containerViewId != 0) {
            if (containerViewId == View.NO_ID) {
                throw new IllegalArgumentException("Can't add fragment "
                        + fragment + " with tag " + tag + " to container view with no id");
            }
            if (fragment.mFragmentId != 0 && fragment.mFragmentId != containerViewId) {
                throw new IllegalStateException("Can't change container ID of fragment "
                        + fragment + ": was " + fragment.mFragmentId
                        + " now " + containerViewId);
            }
            // 設(shè)置宿主ID為布局ID
            fragment.mContainerId = fragment.mFragmentId = containerViewId;
        }
        // 將fragment和opcmd指令封裝成一個Op對象,Op對象其是對于Fragment的操作對象舌涨,封裝fragment的相關(guān)操作信息
        addOp(new Op(opcmd, fragment));
    }

6.FragmentTransaction#addOp

    void addOp(Op op) {
        // 將每個Fragment相關(guān)的操作對象添加到ArrayList集合中糯耍,用于提交的時候使用
        mOps.add(op);
        op.mEnterAnim = mEnterAnim;
        op.mExitAnim = mExitAnim;
        op.mPopEnterAnim = mPopEnterAnim;
        op.mPopExitAnim = mPopExitAnim;
    }

7.BackStackRecord#commit

BackStackRecord的提交有四個方法,這里做統(tǒng)一分析:然后最后就分析commit()的后續(xù)流程囊嘉,因為大體相同温技,主要就是異步和同步提交不同。

    // commit() 在主線程中異步執(zhí)行扭粱,其實也是 Handler 拋出任務(wù)舵鳞,等待主線程調(diào)度執(zhí)行。
    // commit需要在Activity保存狀態(tài)之前提交琢蛤,否則會報錯蜓堕。
    // 因為Activity出現(xiàn)異常需要恢復(fù)狀態(tài),在保存狀態(tài)之后的commit會丟失
    @Override
    public int commit() {
        return commitInternal(false);
    }

    // commitAllowingStateLoss() 也是異步執(zhí)行博其,但它的不同之處在于套才,允許在 Activity 
    // 保存狀態(tài)之后調(diào)用,也就是說它遇到狀態(tài)丟失不會報錯慕淡。
    @Override
    public int commitAllowingStateLoss() {
        return commitInternal(true);
    }

    // 這是同步執(zhí)行的背伴。立即提交事務(wù)。與FragmentManager.executePendingTransactions
    // 類似峰髓,但是推薦使用commitNow傻寂。因為executePendingTransactions會一次性
    // 執(zhí)行所有待執(zhí)行的事務(wù),可能會有副作用疾掰。而且executePendingTransactions方法提交
    // 的事務(wù)可能不會被添加到FragmentManager的回退棧中,因為這樣直接提交可能會影響
    // 其他異步執(zhí)行任務(wù)在棧中的順序
    // commitNow的提交也不能在狀態(tài)保存之后進行
    // TODO:這兩個方法在調(diào)用的時候徐紧,是禁止使用回退棧功能的
    @Override
    public void commitNow() {
        disallowAddToBackStack();
        mManager.execSingleAction(this, false);
    }

    @Override
    public void commitNowAllowingStateLoss() {
        disallowAddToBackStack();
        mManager.execSingleAction(this, true);
    }

8.BackStackRecord#commitInternal

    int commitInternal(boolean allowStateLoss) {
        if (mCommitted) throw new IllegalStateException("commit already called");
        if (FragmentManager.isLoggingEnabled(Log.VERBOSE)) {
            Log.v(TAG, "Commit: " + this);
            LogWriter logw = new LogWriter(TAG);
            PrintWriter pw = new PrintWriter(logw);
            dump("  ", pw);
            pw.close();
        }
        mCommitted = true;
        // 這里的index个绍,其實是記錄當(dāng)前事務(wù)可以放置的位置的
        // 如果是fragment-1.1.0版本,是采用兩個集合的方式浪汪,一個集合保存BackStackRecord
        // 另一個集合保存因為回退之后巴柿,空出來的位置的索引
        // 但是在fragment-1.2.1版本中,采用的是AtomicInteger死遭,比較并交換的做法
        if (mAddToBackStack) {
            // 這里是回退椆慊郑可用的情況,則需要計算一個index
            // 這里因為Androidx版本的區(qū)別呀潭,實現(xiàn)也不同钉迷。
            // 這里的代碼是fragment-1.2.1版本的庫
            mIndex = mManager.allocBackStackIndex();
            // 如果是fragment-1.1.0的庫至非,則與這里實現(xiàn)不同,如下所示
            // mIndex = mManager.allocBackStackIndex(this);
        } else {
            mIndex = -1;
        }
        mManager.enqueueAction(this, allowStateLoss);
        return mIndex;
    }

9.FragmentManager#allocBackStackIndex()

這是fragment-1.2.1-androidx的源碼
這里采用AtomicInteger糠聪,是為了保證在異步提交事務(wù)處理的時候荒椭,保證index的一個原子性

    int allocBackStackIndex() {
        return mBackStackIndex.getAndIncrement();
    }

對比fragment-1.1.0-androidx的源碼
在這里,是采用兩個ArrayList數(shù)組的方式舰蟆,一個用來保存當(dāng)前提交的事務(wù)趣惠,而另一個是用來保存當(dāng)前事務(wù)集合中的可用位置,這樣說可能比較抽象身害,看源碼分析味悄。

    public int allocBackStackIndex(BackStackRecord bse) {
        synchronized (this) {
            // 第一次提交的時候,mAvailBackStackIndices是為null或者size==0的
            // 所以執(zhí)行if條件
            if (mAvailBackStackIndices == null || mAvailBackStackIndices.size() <= 0) {
                // 初始化mBackStackIndices保存事務(wù)
                if (mBackStackIndices == null) {
                    mBackStackIndices = new ArrayList<BackStackRecord>();
                }
                // 找到當(dāng)前添加的事務(wù)的索引位置塌鸯,在這里侍瑟,因為是添加到了mBackStackIndices的末尾
                // 所以添加的集合的索引位置其實就是添加之前的集合的長度
                int index = mBackStackIndices.size();
                if (DEBUG) Log.v(TAG, "Setting back stack index " + index + " to " + bse);
                mBackStackIndices.add(bse);
                return index;

            } else {
                int index = mAvailBackStackIndices.remove(mAvailBackStackIndices.size()-1);
                if (DEBUG) Log.v(TAG, "Adding back stack index " + index + " with " + bse);
                mBackStackIndices.set(index, bse);
                return index;
            }
        }
    }
    // 向之前回退位置的存儲集合位置上添加事務(wù)
    public void setBackStackIndex(int index, BackStackRecord bse) {
        synchronized (this) {
            if (mBackStackIndices == null) {
                mBackStackIndices = new ArrayList<BackStackRecord>();
            }
            int N = mBackStackIndices.size();
            // 如果index小于mBackStackIndices的長度,說明mBackStackIndices中有取出添加到回退棧的事務(wù)
            // 那么基于復(fù)用原則丙猬,繼續(xù)復(fù)用之前取出的位置存放當(dāng)前添加的事務(wù)
            if (index < N) {
                if (DEBUG) Log.v(TAG, "Setting back stack index " + index + " to " + bse);
                mBackStackIndices.set(index, bse);
            } else {
                // 如果存儲集合的長度是小于要添加的位置涨颜,則向集合的末尾添加事務(wù)
                while (N < index) {
                    mBackStackIndices.add(null);
                    if (mAvailBackStackIndices == null) {
                        mAvailBackStackIndices = new ArrayList<Integer>();
                    }
                    if (DEBUG) Log.v(TAG, "Adding available back stack index " + N);
                    mAvailBackStackIndices.add(N);
                    N++;
                }
                if (DEBUG) Log.v(TAG, "Adding back stack index " + index + " with " + bse);
                // 這里是index==N的條件
                mBackStackIndices.add(bse);
            }
        }
    }
    // 釋放存儲事務(wù)集合中的事務(wù)
    public void freeBackStackIndex(int index) {
        synchronized (this) {
            // 在釋放mBackStackIndices中的事務(wù)的時候,并不是單純的將集合的index位置釋放茧球,然后重新排序集合
            // 而是采用一個null來填充咐低,用于下一次的復(fù)用
            mBackStackIndices.set(index, null);
            if (mAvailBackStackIndices == null) {
                mAvailBackStackIndices = new ArrayList<Integer>();
            }
            if (DEBUG) Log.v(TAG, "Freeing back stack index " + index);
            // 這里存儲的其實就是之前被釋放的事務(wù)的位置,這樣的做法袜腥,其實就是方便
            // 下一次添加事務(wù)的時候见擦,能夠精準的找到mBackStackIndices中對應(yīng)的位置存放事務(wù)
            mAvailBackStackIndices.add(index);
        }
    }

10.FragmentManager#enqueueAction

    void enqueueAction(@NonNull OpGenerator action, boolean allowStateLoss) {
        // 判斷是否需要檢查狀態(tài),即是否允許在保存狀態(tài)之后提交事務(wù)進行丟棄
        // 如果allowStateLoss是false羹令,則需要檢查當(dāng)前事務(wù)提交的時候是否已經(jīng)進行onSaveInstanceState操作
        if (!allowStateLoss) {
            if (mHost == null) {
                if (mDestroyed) {
                    throw new IllegalStateException("FragmentManager has been destroyed");
                } else {
                    throw new IllegalStateException("FragmentManager has not been attached to a "
                            + "host.");
                }
            }
            checkStateLoss();
        }
        // mPendingActions中添加的是正在等待處理的事務(wù)
        synchronized (mPendingActions) {
            // 如果HostCallbacks對象為null鲤屡,判斷allowStateLoss是否為true
            // 如果為true,則直接return福侈,否則拋出異常酒来,提示activity已經(jīng)被銷毀
            if (mHost == null) {
                if (allowStateLoss) {
                    // This FragmentManager isn't attached, so drop the entire transaction.
                    return;
                }
                throw new IllegalStateException("Activity has been destroyed");
            }
            mPendingActions.add(action);
            // 異步執(zhí)行提交操作
            scheduleCommit();
        }
    }

11.FragmentManager#scheduleCommit

    // 執(zhí)行異步任務(wù)
    void scheduleCommit() {
        synchronized (mPendingActions) {
            boolean postponeReady =
                    mPostponedTransactions != null && !mPostponedTransactions.isEmpty();
            boolean pendingReady = mPendingActions.size() == 1;
            if (postponeReady || pendingReady) {
                // 這里就是采用之前添加到HostCallbacks對象中的Handler來執(zhí)行異步任務(wù)操作
                // 首先刪除上一次執(zhí)行的提交的任務(wù)
                mHost.getHandler().removeCallbacks(mExecCommit);
                // 然后再執(zhí)行當(dāng)前新的提交請求
                // mExecCommit其實是一個Runnable對象
                mHost.getHandler().post(mExecCommit);
                updateOnBackPressedCallbackEnabled();
            }
        }
    }

12.FragmentManager#mExecCommit對象

    private Runnable mExecCommit = new Runnable() {
        @Override
        public void run() {
            // 由HostCallbacks中的Handler進行執(zhí)行該任務(wù)
            execPendingActions(true);
        }
    };

13.FragmentManager#execPendingActions

    // 只能從主線程調(diào)用該方法
    boolean execPendingActions(boolean allowStateLoss) {
    // 確保執(zhí)行是處于就緒階段,即沒有正在執(zhí)行的事務(wù)肪凛,也HostCallbacks也不為null
    // 且是在主線程中堰汉,并且初始化mTmpRecords和mTmpIsPop
    // 這里就是針對execPendingActions的方法執(zhí)行的線程檢查的操作
        ensureExecReady(allowStateLoss);

        boolean didSomething = false;
    // 這里的操作,其實就是在mPendingActions中取出BackStackRecord
    // mPendingActions中存的是OpGenerator伟墙,而BackStackRecord實現(xiàn)了該接口
    // mTmpRecords存的就是BackStackRecord
    // 所以這里的目的就算將待執(zhí)行的事務(wù)添加到mTmpRecords
    // 而在mTmpIsPop對應(yīng)位置會根據(jù)是否允許添加到回退棧而設(shè)置true還是false
    // 這里如果mPendingActions為null翘鸭,則直接返回false
        while (generateOpsForPendingActions(mTmpRecords, mTmpIsPop)) {
            mExecutingActions = true;
            try {
            // 這里是刪除冗余操作,并且執(zhí)行事務(wù)
            // 所謂的冗余操作:比如一次事務(wù)提交戳葵,對一個Fragment進行了add
            // 又進行了remove就乓,然后又進行了add,這樣只有最后一次add有效
            // 在這里會修改事務(wù)的狀態(tài),比如將replace的事務(wù)變成ADD的
            // 最終就會執(zhí)行處理事務(wù)
            // 如果沒有回退棧相關(guān)生蚁,則是調(diào)用事務(wù)BackStackRecord.executeOps方法
                removeRedundantOperationsAndExecute(mTmpRecords, mTmpIsPop);
            } finally {
                cleanupExec();
            }
            didSomething = true;
        }

        updateOnBackPressedCallbackEnabled();
    // 執(zhí)行延遲啟動的Fragment噩翠,修改其狀態(tài)
        doPendingDeferredStart();
    // 這里為了防止列表錯誤,將mActive的值置為null
    // 而不是在Fragment變?yōu)榉腔顒訝顟B(tài)的時候?qū)⑵鋭h除邦投。
    // 但是在執(zhí)行事務(wù)結(jié)束時會清理列表
        mFragmentStore.burpActive();

        return didSomething;
    }

14.FragmentManager#removeRedundantOperationsAndExecute

這里的主要目的就是為了移除事務(wù)提交過程中伤锚,事務(wù)列表中冗余的BackStackRecord對象。

    private void removeRedundantOperationsAndExecute(@NonNull ArrayList<BackStackRecord> records,
            @NonNull ArrayList<Boolean> isRecordPop) {
        if (records.isEmpty()) {
            return;
        }

        if (records.size() != isRecordPop.size()) {
            throw new IllegalStateException("Internal error with the back stack records");
        }

      // 針對與計劃處理的事務(wù)有交互的任何延遲的事務(wù)志衣,進行強制執(zhí)行
      // 不過這些事務(wù)是過去延遲處理屯援,但是當(dāng)前已經(jīng)準備好的事務(wù)
        executePostponedTransaction(records, isRecordPop);

        final int numRecords = records.size();
        int startIndex = 0;
        for (int recordNum = 0; recordNum < numRecords; recordNum++) {
            final boolean canReorder = records.get(recordNum).mReorderingAllowed;
            if (!canReorder) {
                // 執(zhí)行先前的所有事務(wù)
                if (startIndex != recordNum) {
                    executeOpsTogether(records, isRecordPop, startIndex, recordNum);
                }
                // 執(zhí)行所有不允許重新排序的出棧操作或者事務(wù)的添加操作
                int reorderingEnd = recordNum + 1;
                if (isRecordPop.get(recordNum)) {
                    while (reorderingEnd < numRecords
                            && isRecordPop.get(reorderingEnd)
                            && !records.get(reorderingEnd).mReorderingAllowed) {
                        reorderingEnd++;
                    }
                }
                executeOpsTogether(records, isRecordPop, recordNum, reorderingEnd);
                startIndex = reorderingEnd;
                recordNum = reorderingEnd - 1;
            }
        }
        if (startIndex != numRecords) {
            executeOpsTogether(records, isRecordPop, startIndex, numRecords);
        }
    }

15.FragmentManager#executeOpsTogether

    private void executeOpsTogether(@NonNull ArrayList<BackStackRecord> records,
            @NonNull ArrayList<Boolean> isRecordPop, int startIndex, int endIndex) {
        final boolean allowReordering = records.get(startIndex).mReorderingAllowed;
        boolean addToBackStack = false;
        // 添加Fragment到集合中,該集合是ADD狀態(tài)的Fragment集合
        if (mTmpAddedFragments == null) {
            mTmpAddedFragments = new ArrayList<>();
        } else {
            mTmpAddedFragments.clear();
        }
        mTmpAddedFragments.addAll(mFragmentStore.getFragments());
        Fragment oldPrimaryNav = getPrimaryNavigationFragment();
        for (int recordNum = startIndex; recordNum < endIndex; recordNum++) {
            final BackStackRecord record = records.get(recordNum);
            final boolean isPop = isRecordPop.get(recordNum);
            if (!isPop) {
                // 如果是不允許出棧的蠢涝,修改事務(wù)的操作狀態(tài)
                // 比如將replace的操作也變成了ADD操作,這里其實就是想ADD狀態(tài)集合添加Fragment
                oldPrimaryNav = record.expandOps(mTmpAddedFragments, oldPrimaryNav);
            } else {
                oldPrimaryNav = record.trackAddedFragmentsInPop(mTmpAddedFragments, oldPrimaryNav);
            }
            addToBackStack = addToBackStack || record.mAddToBackStack;
        }
        mTmpAddedFragments.clear();

        if (!allowReordering) {
            FragmentTransition.startTransitions(this, records, isRecordPop, startIndex, endIndex,
                    false, mFragmentTransitionCallback);
        }
        // 這里是具體執(zhí)行對Fragment的add阅懦、replace和二、hide、show等操作的
        executeOps(records, isRecordPop, startIndex, endIndex);

        int postponeIndex = endIndex;
        // 判斷是否允許重新排序
        if (allowReordering) {
            ArraySet<Fragment> addedFragments = new ArraySet<>();
            addAddedFragments(addedFragments);
            postponeIndex = postponePostponableTransactions(records, isRecordPop,
                    startIndex, endIndex, addedFragments);
            makeRemovedFragmentsInvisible(addedFragments);
        }

        if (postponeIndex != startIndex && allowReordering) {
            // need to run something now
            FragmentTransition.startTransitions(this, records, isRecordPop, startIndex,
                    postponeIndex, true, mFragmentTransitionCallback);
            moveToState(mCurState, true);
        }

        for (int recordNum = startIndex; recordNum < endIndex; recordNum++) {
            final BackStackRecord record = records.get(recordNum);
            final boolean isPop = isRecordPop.get(recordNum);
            if (isPop && record.mIndex >= 0) {
                record.mIndex = -1;
            }
            record.runOnCommitRunnables();
        }
        if (addToBackStack) {
            reportBackStackChanged();
        }
    }

16.BackStackRecord#expandOps

這里主要是找到舊的Fragment的導(dǎo)航

    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:
                    added.add(op.mFragment);
                    break;
                case OP_REMOVE:
                case OP_DETACH: {
                    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: {
                    // REPLACE狀態(tài)耳胎,如果是已經(jīng)添加的惯吕,則需要刪除已經(jīng)添加的,然后再一次添加新的
                    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) {
                            // 判斷舊的Fragment和當(dāng)前要添加的Fragment是否一致
                            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++;
                            }
                        }
                    }
                    // 如果是已經(jīng)添加怕午,則先刪除已經(jīng)添加的废登,然后在加入新的
                    // 再將op.mCmd改成OP_ADD
                    if (alreadyAdded) {
                        mOps.remove(opNum);
                        opNum--;
                    } else {
                        op.mCmd = OP_ADD;
                        added.add(f);
                    }
                }
                break;
                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;
    }

17.FragmentManager#executeOps

    private static void executeOps(@NonNull ArrayList<BackStackRecord> records,
            @NonNull 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);
                // Only execute the add operations at the end of
                // all transactions.
                boolean moveToState = i == (endIndex - 1);
                record.executePopOps(moveToState);
            } else {
                record.bumpBackStackNesting(1);
                // 執(zhí)行事務(wù)
                record.executeOps();
            }
        }
    }

18.BackStackRecord#executeOps

    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);
            }
            switch (op.mCmd) {
                case OP_ADD:
                    f.setNextAnim(op.mEnterAnim);
                    mManager.setExitAnimationOrder(f, false);
                    mManager.addFragment(f);
                    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.setExitAnimationOrder(f, false);
                    mManager.showFragment(f);
                    break;
                case OP_DETACH:
                    f.setNextAnim(op.mExitAnim);
                    mManager.detachFragment(f);
                    break;
                case OP_ATTACH:
                    f.setNextAnim(op.mEnterAnim);
                    mManager.setExitAnimationOrder(f, false);
                    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) {
            // 事務(wù)提交之后,根據(jù)當(dāng)前狀態(tài)郁惜,執(zhí)行fragment的生命周期
            mManager.moveToState(mManager.mCurState, true);
        }
    }

19.FragmentManager#addFragment/removeFragment/hideFragment/showFragment/detachFragment/attachFragment

    void addFragment(@NonNull Fragment fragment) {
        if (isLoggingEnabled(Log.VERBOSE)) Log.v(TAG, "add: " + fragment);
        makeActive(fragment);
        if (!fragment.mDetached) {
            // 向mAdded集合中添加fragment堡距,mAdded集合是保存添加的Fragment
            // 用于在moveToState的處理添加的Fragment
            mFragmentStore.addFragment(fragment);
            fragment.mRemoving = false;
            if (fragment.mView == null) {
                // 添加之后,設(shè)置隱藏狀態(tài)為false
                fragment.mHiddenChanged = false;
            }
            if (isMenuAvailable(fragment)) {
                mNeedMenuInvalidate = true;
            }
        }
    }

    void removeFragment(@NonNull Fragment fragment) {
        if (isLoggingEnabled(Log.VERBOSE)) {
            Log.v(TAG, "remove: " + fragment + " nesting=" + fragment.mBackStackNesting);
        }
        final boolean inactive = !fragment.isInBackStack();
        if (!fragment.mDetached || inactive) {
            // 從mAdded集合中刪除fragment
            mFragmentStore.removeFragment(fragment);
            if (isMenuAvailable(fragment)) {
                mNeedMenuInvalidate = true;
            }
            fragment.mRemoving = true;
            setVisibleRemovingFragment(fragment);
        }
    }

    void hideFragment(@NonNull Fragment fragment) {
        if (isLoggingEnabled(Log.VERBOSE)) Log.v(TAG, "hide: " + fragment);
        if (!fragment.mHidden) {
            // 設(shè)置fragment的隱藏狀態(tài)為true
            fragment.mHidden = true;
            // Toggle hidden changed so that if a fragment goes through show/hide/show
            // it doesn't go through the animation.
            fragment.mHiddenChanged = !fragment.mHiddenChanged;
            setVisibleRemovingFragment(fragment);
        }
    }

    void showFragment(@NonNull Fragment fragment) {
        if (isLoggingEnabled(Log.VERBOSE)) Log.v(TAG, "show: " + fragment);
        if (fragment.mHidden) {
            // 設(shè)置fragment的隱藏狀態(tài)
            fragment.mHidden = false;
            // Toggle hidden changed so that if a fragment goes through show/hide/show
            // it doesn't go through the animation.
            fragment.mHiddenChanged = !fragment.mHiddenChanged;
        }
    }

    void detachFragment(@NonNull Fragment fragment) {
        if (isLoggingEnabled(Log.VERBOSE)) Log.v(TAG, "detach: " + fragment);
        if (!fragment.mDetached) {
            fragment.mDetached = true;
            if (fragment.mAdded) {
                // We are not already in back stack, so need to remove the fragment.
                if (isLoggingEnabled(Log.VERBOSE)) Log.v(TAG, "remove from detach: " + fragment);
                mFragmentStore.removeFragment(fragment);
                if (isMenuAvailable(fragment)) {
                    mNeedMenuInvalidate = true;
                }
                setVisibleRemovingFragment(fragment);
            }
        }
    }

    void attachFragment(@NonNull Fragment fragment) {
        if (isLoggingEnabled(Log.VERBOSE)) Log.v(TAG, "attach: " + fragment);
        if (fragment.mDetached) {
            fragment.mDetached = false;
            if (!fragment.mAdded) {
                mFragmentStore.addFragment(fragment);
                if (isLoggingEnabled(Log.VERBOSE)) Log.v(TAG, "add from attach: " + fragment);
                if (isMenuAvailable(fragment)) {
                    mNeedMenuInvalidate = true;
                }
            }
        }
    }

20.FragmentManager#moveToState

    void moveToState(int newState, boolean always) {
        if (mHost == null && newState != Fragment.INITIALIZING) {
            throw new IllegalStateException("No activity");
        }

        if (!always && newState == mCurState) {
            return;
        }

        mCurState = newState;

        // Must add them in the proper order. mActive fragments may be out of order
        for (Fragment f : mFragmentStore.getFragments()) {
            moveFragmentToExpectedState(f);
        }

        // Now iterate through all active fragments. These will include those that are removed
        // and detached.
        for (Fragment f : mFragmentStore.getActiveFragments()) {
            if (f != null && !f.mIsNewlyAdded) {
                moveFragmentToExpectedState(f);
            }
        }

        startPendingDeferredFragments();

        if (mNeedMenuInvalidate && mHost != null && mCurState == Fragment.RESUMED) {
            mHost.onSupportInvalidateOptionsMenu();
            mNeedMenuInvalidate = false;
        }
    }

21.FragmentManager#moveFragmentToExpectedState

    void moveFragmentToExpectedState(@NonNull Fragment f) {
        if (!mFragmentStore.containsActiveFragment(f.mWho)) {
            if (isLoggingEnabled(Log.DEBUG)) {
                Log.d(TAG, "Ignoring moving " + f + " to state " + mCurState
                        + "since it is not added to " + this);
            }
            return;
        }
        // 在CREATED狀態(tài)的時候會創(chuàng)建View兆蕉,保存在Fragment
        moveToState(f);

        if (f.mView != null) {
            // Move the view if it is out of order
            Fragment underFragment = mFragmentStore.findFragmentUnder(f);
            if (underFragment != null) {
                final View underView = underFragment.mView;
                // make sure this fragment is in the right order.
                final ViewGroup container = f.mContainer;
                int underIndex = container.indexOfChild(underView);
                int viewIndex = container.indexOfChild(f.mView);
                if (viewIndex < underIndex) {
                    container.removeViewAt(viewIndex);
                    container.addView(f.mView, underIndex);
                }
            }
            if (f.mIsNewlyAdded && f.mContainer != null) {
                // Make it visible and run the animations
                if (f.mPostponedAlpha > 0f) {
                    f.mView.setAlpha(f.mPostponedAlpha);
                }
                f.mPostponedAlpha = 0f;
                f.mIsNewlyAdded = false;
                // run animations:
                FragmentAnim.AnimationOrAnimator anim = FragmentAnim.loadAnimation(
                        mHost.getContext(), mContainer, f, true);
                if (anim != null) {
                    if (anim.animation != null) {
                        f.mView.startAnimation(anim.animation);
                    } else {
                        anim.animator.setTarget(f.mView);
                        anim.animator.start();
                    }
                }
            }
        }
        // 是否隱藏的狀態(tài)羽戒,如果是true,這執(zhí)行完成隱藏顯示Fragment的操作
        if (f.mHiddenChanged) {
            completeShowHideFragment(f);
        }
    }
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末虎韵,一起剝皮案震驚了整個濱河市易稠,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌包蓝,老刑警劉巖驶社,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異测萎,居然都是意外死亡亡电,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進店門硅瞧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來逊抡,“玉大人,你說我怎么就攤上這事∶暗眨” “怎么了拇勃?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長孝凌。 經(jīng)常有香客問我方咆,道長,這世上最難降的妖魔是什么蟀架? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任瓣赂,我火速辦了婚禮,結(jié)果婚禮上片拍,老公的妹妹穿的比我還像新娘煌集。我一直安慰自己,他們只是感情好捌省,可當(dāng)我...
    茶點故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布苫纤。 她就那樣靜靜地躺著,像睡著了一般纲缓。 火紅的嫁衣襯著肌膚如雪卷拘。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天祝高,我揣著相機與錄音栗弟,去河邊找鬼。 笑死工闺,一個胖子當(dāng)著我的面吹牛乍赫,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播陆蟆,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼耿焊,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了遍搞?” 一聲冷哼從身側(cè)響起罗侯,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎溪猿,沒想到半個月后钩杰,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡诊县,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年讲弄,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片依痊。...
    茶點故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡避除,死狀恐怖怎披,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情瓶摆,我是刑警寧澤凉逛,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站群井,受9級特大地震影響状飞,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜书斜,卻給世界環(huán)境...
    茶點故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一诬辈、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧荐吉,春花似錦焙糟、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至瞧哟,卻和暖如春混巧,著一層夾襖步出監(jiān)牢的瞬間枪向,已是汗流浹背勤揩。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留秘蛔,地道東北人陨亡。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像深员,于是被迫代替她去往敵國和親负蠕。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,713評論 2 354

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