1. 程式人生 > >原始碼解析Fragment 返回棧原理

原始碼解析Fragment 返回棧原理

返回棧涉及的類

在看本文前需要熟悉Fragment 的使用,不清楚的可先看:Fragment使用詳解

本文原始碼都是都是v25 的support v4 包下的原始碼。

基本操作:getFragmentManager().beginTransaction().add(R.id.container, fragment).addToBackStack(null).commit();
getFragmentManager():實際返回值是FragmentManagerImpl 物件。
beginTransaction():實際返回值是BackStackRecord 物件。

  • BackStackRecord.Op
    代表Fragment 事務中的一次操作,如add、remove等。

  • BackStackRecord
    一個BackStackRecord 代表一次Fragment 事務
    BackStackRecord extends FragmentTransaction implements FragmentManager.BackStackEntry, FragmentManagerImpl.OpGenerator 實現了OpGenerator
    Field:
    1、ArrayList<BackStackRecord.Op> mOps:儲存一次Fragment 事務的所有Op 操作。
    2、FragmentManagerImpl mManager:儲存getFragmentManager() 的返回值。

  • FragmentManagerImpl.OpGenerator
    相當於BackStackRecord。一個OpGenerator 物件能產生相應的一個BackStackRecord 物件,該BackStackRecord 物件可能是OpGenerator 物件本身也可能來自返回棧。

  • FragmentManagerImpl
    Field:
    1、ArrayList<FragmentManagerImpl.OpGenerator> mPendingActions:存放當前尚未執行的所有事務,用於產生mTmpRecords 和mTmpIsPop。
    2、ArrayList<BackStackRecord> mTmpRecords:存放當前尚未執行的所有事務

    ,由mPendingActions 轉化而來。
    3、ArrayList<Boolean> mTmpIsPop:mTmpRecords 中對應下標下的事務是否是出棧。
    4、ArrayList<BackStackRecord> mBackStack:返回棧,存放mTmpRecords 中進棧的事務。
    5、ArrayList<Fragment> mAdded:存放前臺Fragment,即已呼叫了add() 但尚未進入返回棧或被被銷燬的Fragment。
    6、ArrayList<Fragment> mActive:存放前臺Fragment 和返回棧中的Fragment。
    7、ArrayList<Fragment> mTmpAddedFragments:臨時的mAdded 。

看原始碼前先了解下:
1、Fragment 的各種狀態:

static final int INITIALIZING = 0;     // Not yet created.銷燬。
static final int CREATED = 1;          // Created.沒有檢視但fragment已建立,比如:fragment處於返回棧中。
static final int ACTIVITY_CREATED = 2; // The activity has finished its creation.宿主Activity已建立完畢,就是fragment生命週期已呼叫到onActivityCreated(),已建立檢視。
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.聚焦

事務提交

流程

  1. BackStackRecord:addToBackStack() //若呼叫則標誌事務進棧,否則不進棧。
  2. BackStackRecord:commit()
  3. BackStackRecord:commitInternal()
  4. FragmentManagerImpl:enqueueAction() //BackStackRecord加入mPendingActions。
  5. FragmentManagerImpl:generateOpsForPendingActions() //mPendingActions轉換為mTmpRecords 和mTmpIsPop。
  6. FragmentManagerImpl:executeOpsTogether() //遍歷mTmpRecords。1、將Op是replace 的替換為多個remove 和一個add。2、執行所有Op,更新mAdded 和mActive。每個事務的最後一個Op時,對mAdded 和mActive 中所有Fragment 切換生命週期到預期的狀態,同時,在此過程中對每一個從前臺退回到返回棧的Fragment呼叫它的頂級View 的saveHierarchyState() 儲存View狀態,對每一個從返回棧出棧變為前臺的Fragment呼叫它的頂級View的restoreHierarchyState() 恢復View狀態。

原始碼

BackStackRecord:

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;
}

public int commit() {
    return commitInternal(false);
}

int commitInternal(boolean allowStateLoss) {
    if (mCommitted) throw new IllegalStateException("commit already called");
    mCommitted = true;
    if (mAddToBackStack) {
        mIndex = mManager.allocBackStackIndex(this);
    } else {
        mIndex = -1;
    }
    mManager.enqueueAction(this, allowStateLoss);//該BackStackRecord物件加入mPendingActions
    return mIndex;
}

FragmentManagerImpl:

/**
 * Adds an action to the queue of pending actions.
 */
public void enqueueAction(OpGenerator action, boolean allowStateLoss) {
    if (!allowStateLoss) {
        checkStateLoss();
    }
    synchronized (this) {
        if (mDestroyed || mHost == null) {
            throw new IllegalStateException("Activity has been destroyed");
        }
        if (mPendingActions == null) {
            mPendingActions = new ArrayList<>();
        }
        mPendingActions.add(action);//
        scheduleCommit();//用UI執行緒的Handler傳送Runnable
    }
}

private 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);//傳送runnable
        }
    }
}

Runnable mExecCommit = new Runnable() {
    @Override
    public void run() {
        execPendingActions();
    }
};

/**
 * Only call from main thread!
 */
public boolean execPendingActions() {
    ensureExecReady(true);

    boolean didSomething = false;
    while (generateOpsForPendingActions(mTmpRecords, mTmpIsPop)) {//mPendingActions 轉換為mTmpRecords 和mTmpIsPop。
        mExecutingActions = true;
        try {
            optimizeAndExecuteOps(mTmpRecords, mTmpIsPop);//優化並處理所有Op
        } finally {
            cleanupExec();
        }
        didSomething = true;
    }

    doPendingDeferredStart();

    return didSomething;
}

/**
 * Adds all records in the pending actions to records and whether they are add or pop
 * operations to isPop. After executing, the pending actions will be empty.
 */
private boolean generateOpsForPendingActions(ArrayList<BackStackRecord> records,
        ArrayList<Boolean> isPop) {
    int numActions;
    synchronized (this) {
        if (mPendingActions == null || mPendingActions.size() == 0) {
            return false;
        }

        numActions = mPendingActions.size();
        for (int i = 0; i < numActions; i++) {
            mPendingActions.get(i).generateOps(records, isPop);
            //若該事務是出棧,則從mBackStack 中取出一個事務即BackStackRecord加入mTmpRecords;
            //否則,將當前action 加入mTmpRecords,若該事務進棧還要新增到mBackStack中。
        }
        mPendingActions.clear();//清空
        mHost.getHandler().removeCallbacks(mExecCommit);
    }
    return numActions > 0;
}

private void optimizeAndExecuteOps(ArrayList<BackStackRecord> records,
        ArrayList<Boolean> isRecordPop) {
    ......

    // Force start of any postponed transactions that interact with scheduled transactions:
    executePostponedTransaction(records, isRecordPop);

    final int numRecords = records.size();
    int startIndex = 0;
    for (int recordNum = 0; recordNum < numRecords; recordNum++) {
        final boolean canOptimize = records.get(recordNum).mAllowOptimization;
        if (!canOptimize) {
            // execute all previous transactions
            if (startIndex != recordNum) {
                executeOpsTogether(records, isRecordPop, startIndex, recordNum);
            }
            // execute all unoptimized pop operations together or one add operation
            int optimizeEnd = recordNum + 1;
            if (isRecordPop.get(recordNum)) {
                while (optimizeEnd < numRecords
                        && isRecordPop.get(optimizeEnd)
                        && !records.get(optimizeEnd).mAllowOptimization) {
                    optimizeEnd++;
                }
            }
            executeOpsTogether(records, isRecordPop, recordNum, optimizeEnd);
            startIndex = optimizeEnd;
            recordNum = optimizeEnd - 1;
        }
    }
    if (startIndex != numRecords) {
        executeOpsTogether(records, isRecordPop, startIndex, numRecords);
    }
}


/**
 * Optimizes a subset of a list of BackStackRecords, all of which either allow optimization or
 * do not allow optimization.
 */
private void executeOpsTogether(ArrayList<BackStackRecord> records,
        ArrayList<Boolean> isRecordPop, int startIndex, int endIndex) {
    final boolean allowOptimization = records.get(startIndex).mAllowOptimization;
    boolean addToBackStack = false;
    if (mTmpAddedFragments == null) {
        mTmpAddedFragments = new ArrayList<>();
    } else {
        mTmpAddedFragments.clear();
    }
    if (mAdded != null) {
        mTmpAddedFragments.addAll(mAdded);
    }
    //遍歷mTmpRecords,優化Op操作,根據mTmpAddedFragments 去除不必要的Op操作。
    for (int recordNum = startIndex; recordNum < endIndex; recordNum++) {
        final BackStackRecord record = records.get(recordNum);
        final boolean isPop = isRecordPop.get(recordNum);
        if (!isPop) {
            //替換replac操作為多個remove和一個add操作,
            //進棧的事務同樣也是在這裡替換replace操作的,因此該事務出棧時無需再次進行替換。
            record.expandReplaceOps(mTmpAddedFragments);
        } else {
            record.trackAddedFragmentsInPop(mTmpAddedFragments);
        }
        addToBackStack = addToBackStack || record.mAddToBackStack;
    }
    mTmpAddedFragments.clear();//用完立刻就清空

    if (!allowOptimization) {
        FragmentTransition.startTransitions(this, records, isRecordPop, startIndex, endIndex,
                false);
    }
    executeOps(records, isRecordPop, startIndex, endIndex);//執行所有Op操作

    ......
    if (addToBackStack) {
        reportBackStackChanged();//觸發監聽器
    }
}

/**
 * Run the operations in the BackStackRecords, either to push or pop.
 */
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);
            // Only execute the add operations at the end of
            // all transactions.
            boolean moveToState = i == (endIndex - 1);//最後一個事務時需moveToState 為true,
            record.executePopOps(moveToState);//對出棧事務的所有Op進行逆操作
        } else {
            record.bumpBackStackNesting(1);
            record.executeOps();//執行非出棧事務的所有Op操作
        }
    }
}

BackStackRecord:

/**
 * Reverses the execution of the operations within this transaction. The Fragment states will
 * only be modified if optimizations are not allowed.
 */
void executePopOps(boolean moveToState) {
    for (int opNum = mOps.size() - 1; opNum >= 0; opNum--) {
        final Op op = mOps.get(opNum);
        Fragment f = op.fragment;
        f.setNextTransition(FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle);
        switch (op.cmd) {
            case OP_ADD:
                f.setNextAnim(op.popExitAnim);
                mManager.removeFragment(f);
                break;
            case OP_REMOVE:
                f.setNextAnim(op.popEnterAnim);
                mManager.addFragment(f, false);
                break;
            case OP_HIDE:
                f.setNextAnim(op.popEnterAnim);
                mManager.showFragment(f);
                break;
            case OP_SHOW:
                f.setNextAnim(op.popExitAnim);
                mManager.hideFragment(f);
                break;
            case OP_DETACH:
                f.setNextAnim(op.popEnterAnim);
                mManager.attachFragment(f);
                break;
            case OP_ATTACH:
                f.setNextAnim(op.popExitAnim);
                mManager.detachFragment(f);
                break;
            default:
                throw new IllegalArgumentException("Unknown cmd: " + op.cmd);
        }
        if (!mAllowOptimization && op.cmd != OP_REMOVE) {
            mManager.moveFragmentToExpectedState(f);
        }
    }
    if (!mAllowOptimization && moveToState) {
        //遍歷完該事務後執行moveToState()對mAdded 和mActive 中的fragment切換生命週期。
        mManager.moveToState(mManager.mCurState, true);
    }
}


/**
 * Executes the operations contained within this transaction. The Fragment states will only
 * be modified if optimizations are not allowed.
 */
void executeOps() {
    final int numOps = mOps.size();
    for (int opNum = 0; opNum < numOps; opNum++) {
        final Op op = mOps.get(opNum);
        final Fragment f = op.fragment;
        f.setNextTransition(mTransition, mTransitionStyle);
        switch (op.cmd) {
            case OP_ADD:
                f.setNextAnim(op.enterAnim);
                mManager.addFragment(f, false);
                break;
            case OP_REMOVE:
                f.setNextAnim(op.exitAnim);
                mManager.removeFragment(f);
                break;
            case OP_HIDE:
                f.setNextAnim(op.exitAnim);
                mManager.hideFragment(f);
                break;
            case OP_SHOW:
                f.setNextAnim(op.enterAnim);
                mManager.showFragment(f);
                break;
            case OP_DETACH:
                f.setNextAnim(op.exitAnim);
                mManager.detachFragment(f);
                break;
            case OP_ATTACH:
                f.setNextAnim(op.enterAnim);
                mManager.attachFragment(f);
                break;
            default:
                throw new IllegalArgumentException("Unknown cmd: " + op.cmd);
        }
        if (!mAllowOptimization && op.cmd != OP_ADD) {
            mManager.moveFragmentToExpectedState(f);
        }
    }
    if (!mAllowOptimization) {
        // Added fragments are added at the end to comply with prior behavior.
        //遍歷完該事務後執行moveToState()對mAdded 和mActive 中的fragment切換生命週期。
        mManager.moveToState(mManager.mCurState, true);
    }
}

FragmentManagerImpl:

public void addFragment(Fragment fragment, boolean moveToStateNow) {
    if (mAdded == null) {
        mAdded = new ArrayList<Fragment>();
    }
    if (DEBUG) Log.v(TAG, "add: " + fragment);
    makeActive(fragment);//更新mActive 列表
    if (!fragment.mDetached) {
        if (mAdded.contains(fragment)) {
            throw new IllegalStateException("Fragment already added: " + fragment);
        }
        mAdded.add(fragment);//更新mAdded 列表
        //更新當前fragment 狀態
        fragment.mAdded = true;
        fragment.mRemoving = false;
        if (fragment.mView == null) {
            fragment.mHiddenChanged = false;
        }
        if (fragment.mHasMenu && fragment.mMenuVisible) {
            mNeedMenuInvalidate = true;
        }
        if (moveToStateNow) {
            moveToState(fragment);
        }
    }
}

//removeFragment()、hideFragment()、showFragment()、detachFragment()、attachFragment()的程式碼功能類似,都是更新mAdded、mActive以及fragment狀態。


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

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

    mCurState = newState;

    if (mActive != null) {
        boolean loadersRunning = false;

        // Must add them in the proper order. mActive fragments may be out of order
        if (mAdded != null) {
            final int numAdded = mAdded.size();
            for (int i = 0; i < numAdded; i++) {//遍歷mAdded,切換每個fragment的生命週期到預期的狀態下
                Fragment f = mAdded.get(i);
                moveFragmentToExpectedState(f);//切換fragment的生命週期到預期的狀態下
                if (f.mLoaderManager != null) {
                    loadersRunning |= f.mLoaderManager.hasRunningLoaders();
                }
            }
        }

        // Now iterate through all active fragments. These will include those that are removed
        // and detached.
        final int numActive = mActive.size();
        for (int i = 0; i < numActive; i++) {//遍歷mActive,切換每個fragment的生命週期到預期的狀態下
            Fragment f = mActive.get(i);
            if (f != null && (f.mRemoving || f.mDetached) && !f.mIsNewlyAdded) {
                moveFragmentToExpectedState(f);//切換fragment的生命週期到預期的狀態下
                if (f.mLoaderManager != null) {
                    loadersRunning |= f.mLoaderManager.hasRunningLoaders();
                }
            }
        }

        ......
    }
}

/**
 * Moves a fragment to its expected final state or the fragment manager's state, depending
 * on whether the fragment manager's state is raised properly.
 */
void moveFragmentToExpectedState(Fragment f) {
    if (f == null) {
        return;
    }
    //切換到預期狀態
    int nextState = mCurState;
    if (f.mRemoving) {
        if (f.isInBackStack()) {//fragment在棧中,想要出棧
            nextState = Math.min(nextState, Fragment.CREATED);
        } else {
            nextState = Math.min(nextState, Fragment.INITIALIZING);
        }
    }
    //據預期的狀態執行相應生命週期方法
    moveToState(f, nextState, f.getNextTransition(), f.getNextTransitionStyle(), false);

    ......
}


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;
    }
    if (f.mRemoving && newState > f.mState) {
        // While removing a fragment, we can't change it to a higher state.
        newState = f.mState;
    }
    // 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;
    }
    if (f.mState < newState) {   //狀態復原:fragment建立或出棧等
        // 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.getAnimatingAway() != 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.setAnimatingAway(null);
            moveToState(f, f.getStateAfterAnimating(), 0, 0, true);
        }
        switch (f.mState) {
            case Fragment.INITIALIZING:
                if (DEBUG) Log.v(TAG, "moveto CREATED: " + f);
                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();
                dispatchOnFragmentPreAttached(f, mHost.getContext(), false);
                f.mCalled = false;
                f.onAttach(mHost.getContext());//呼叫Fragment 的onAttach()。
                if (!f.mCalled) {
                    throw new SuperNotCalledException("Fragment " + f
                            + " did not call through to super.onAttach()");
                }
                if (f.mParentFragment == null) {
                    mHost.onAttachFragment(f);
                } else {
                    f.mParentFragment.onAttachFragment(f);
                }
                dispatchOnFragmentAttached(f, mHost.getContext(), false);

                if (!f.mRetaining) {
                    f.performCreate(f.mSavedFragmentState);//該方法會觸發Fragment 的onCreate()。
                    dispatchOnFragmentCreated(f, f.mSavedFragmentState, false);
                } else {
                    f.restoreChildFragmentState(f.mSavedFragmentState);
                    f.mState = Fragment.CREATED;
                }
                f.mRetaining = false;
                if (f.mFromLayout) {
                    // For fragments that are part of the content view
                    // layout, we need to instantiate the view immediately
                    // and the inflater will take care of adding it.
                    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);
                        f.onViewCreated(f.mView, f.mSavedFragmentState);
                        dispatchOnFragmentViewCreated(f, f.mView, f.mSavedFragmentState, false);
                    } 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) {
                            if (f.mContainerId == View.NO_ID) {
                                throwException(new IllegalArgumentException(
                                        "Cannot create fragment "
                                                + f
                                                + " for a container view with no id"));
                            }
                            container = (ViewGroup) mContainer.onFindViewById(f.mContainerId);
                            if (container == null && !f.mRestored) {
                                String resName;
                                try {
                                    resName = f.getResources().getResourceName(f.mContainerId);
                                } catch (NotFoundException e) {
                                    resName = "unknown";
                                }
                                throwException(new IllegalArgumentException(
                                        "No view found for id 0x"
                                        + Integer.toHexString(f.mContainerId) + " ("
                                        + resName
                                        + ") for fragment " + f));
                            }
                        }
                        f.mContainer = container;
                        f.mView = f.performCreateView(f.getLayoutInflater(
                                f.mSavedFragmentState), container, f.mSavedFragmentState);//會觸發Fragment 的onCreateView()。
                        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 (container != null) {
                                container.addView(f.mView);
                            }
                            if (f.mHidden) {
                                f.mView.setVisibility(View.GONE);
                            }
                            f.onViewCreated(f.mView, f.mSavedFragmentState);
                            dispatchOnFragmentViewCreated(f, f.mView, f.mSavedFragmentState,
                                    false);
                            // Only animate the view if it is visible. This is done after
                            // dispatchOnFragmentViewCreated in case visibility is changed
                            f.mIsNewlyAdded = (f.mView.getVisibility() == View.VISIBLE)
                                    && f.mContainer != null;
                        } else {
                            f.mInnerView = null;
                        }
                    }

                    f.performActivityCreated(f.mSavedFragmentState);//會觸發Fragment 的onActivityCreated()。
                    dispatchOnFragmentActivityCreated(f, f.mSavedFragmentState, false);
                    if (f.mView != null) {
                        f.restoreViewState(f.mSavedFragmentState);//恢復View 狀態。
                    }
                    f.mSavedFragmentState = null;
                }
            case Fragment.ACTIVITY_CREATED:
                if (newState > Fragment.ACTIVITY_CREATED) {
                    f.mState = Fragment.STOPPED;
                }
            case Fragment.STOPPED:
                if (newState > Fragment.STOPPED) {
                    if (DEBUG) Log.v(TAG, "moveto STARTED: " + f);
                    f.performStart();
                    dispatchOnFragmentStarted(f, false);
                }
            case Fragment.STARTED:
                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) {//fragment銷燬或進棧
        switch (f.mState) {
            case Fragment.RESUMED:
                if (newState < Fragment.RESUMED) {
                    if (DEBUG) Log.v(TAG, "movefrom RESUMED: " + f);
                    f.performPause();
                    dispatchOnFragmentPaused(f, false);
                }
            case Fragment.STARTED:
                if (newState < Fragment.STARTED) {
                    if (DEBUG) Log.v(TAG, "movefrom STARTED: " + f);
                    f.performStop();
                    dispatchOnFragmentStopped(f, false);
                }
            case Fragment.STOPPED:
                if (newState < Fragment.STOPPED) {
                    if (DEBUG) Log.v(TAG, "movefrom STOPPED: " + f);
                    f.performReallyStop();
                }
            case Fragment.ACTIVITY_CREATED:
                if (newState < Fragment.ACTIVITY_CREATED) {
                    if (DEBUG) Log.v(TAG, "movefrom ACTIVITY_CREATED: " + f);
                    if (f.mView != null) {
                        // Need to save the current view state if not
                        // done already.
                        if (mHost.onShouldSaveFragmentState(f) && f.mSavedViewState == null) {
                            saveFragmentViewState(f);    //儲存View 狀態。
                        }
                    }
                    f.performDestroyView();
                    dispatchOnFragmentViewDestroyed(f, false);
                    if (f.mView != null && f.mContainer != null) {
                        Animation anim = null;
                        if (mCurState > Fragment.INITIALIZING && !mDestroyed
                                && f.mView.getVisibility() == View.VISIBLE
                                && f.mPostponedAlpha >= 0) {
                            anim = loadAnimation(f, transit, false,
                                    transitionStyle);
                        }
                        f.mPostponedAlpha = 0;
                        if (anim != null) {
                            final Fragment fragment = f;
                            f.setAnimatingAway(f.mView);
                            f.setStateAfterAnimating(newState);
                            final View viewToAnimate = f.mView;
                            anim.setAnimationListener(new AnimateOnHWLayerIfNeededListener(
                                    viewToAnimate, anim) {
                                @Override
                                public void onAnimationEnd(Animation animation) {
                                    super.onAnimationEnd(animation);
                                    if (fragment.getAnimatingAway() != null) {
                                        fragment.setAnimatingAway(null);
                                        moveToState(fragment, fragment.getStateAfterAnimating(),
                                                0, 0, false);
                                    }
                                }
                            });
                            f.mView.startAnimation(anim);
                        }
                        f.mContainer.removeView(f.mView);
                    }
                    f.mContainer = null;
                    f.mView = null;
                    f.mInnerView = null;
                }
            case Fragment.CREATED:
                if (newState < Fragment.CREATED) {
                    if (mDestroyed) {
                        if (f.getAnimatingAway() != 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.getAnimatingAway();
                            f.setAnimatingAway(null);
                            v.clearAnimation();
                        }
                    }
                    if (f.getAnimatingAway() != 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.setStateAfterAnimating(newState);
                        newState = Fragment.CREATED;
                    } else {
                        if (DEBUG) Log.v(TAG, "movefrom CREATED: " + f);
                        if (!f.mRetaining) {
                            f.performDestroy();
                            dispatchOnFragmentDestroyed(f, false);
                        } else {
                            f.mState = Fragment.INITIALIZING;
                        }

                        f.performDetach();
                        dispatchOnFragmentDetached(f, false);
                        if (!keepActive) {
                            if (!f.mRetaining) {
                                makeInactive(f);//fragment被銷燬需要將fragment從mActive 中刪除。
                            } else {
                                f.mHost = null;
                                f.mParentFragment = null;
                                f.mFragmentManager = null;
                            }
                        }
                    }
                }
        }
    }

    //fragment切換到新狀態
    if (f.mState != newState) {
        f.mState = newState;
    }
}

Fragment:

static final int INITIALIZING = 0;     // Not yet created.銷燬。
static final int CREATED = 1;          // Created.沒有檢視但fragment已建立,比如:fragment處於返回棧中。
static final int ACTIVITY_CREATED = 2; // The activity has finished its creation.宿主Activity已建立完畢,就是fragment生命週期已呼叫到onActivityCreated(),已建立檢視。
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.聚焦

事務出棧

流程

  1. FragmentManagerImpl:popBackStack()
  2. FragmentManagerImpl:enqueueAction() //BackStackRecord加入mPendingActions。
  3. FragmentManagerImpl:generateOpsForPendingActions() //mPendingActions轉換為mTmpRecords 和mTmpIsPop。
  4. FragmentManagerImpl:executeOpsTogether() //遍歷mTmpRecords。1、將Op是replace 的替換為多個remove 和一個add。2、執行所有Op,更新mAdded 和mActive。每個事務的最後一個Op時,對mAdded 和mActive 中所有Fragment 切換生命週期到預期狀態,同時,在此過程中對每一個從前臺退回到返回棧的Fragment呼叫它的頂級View 的saveHierarchyState() 儲存View狀態,對每一個從返回棧出棧變為前臺的Fragment呼叫它的頂級View的restoreHierarchyState() 恢復View狀態。

原始碼

FragmentManagerImpl:

public void popBackStack() {
    enqueueAction(new PopBackStackState(null, -1, 0), false);//注意:這裡新增的action不是BackStackRecord。
}

後續的流程更進棧時一樣,都是一樣的程式碼。不同的地方只在mPendingActions 轉換為mTmpRecords時,因mPendingActions 的元素不一樣導致產生的BackStackRecord的來源不一樣:
事務提交:mManager.enqueueAction(this, allowStateLoss); 注:this是BackStackRecord。
事務出棧:enqueueAction(new PopBackStackState(null, -1, 0), false);

下面看下BackStackRecord 和PopBackStackState 產生BackStackRecord的區別。

BackStackRecord:

/**
 * Implementation of {@link FragmentManagerImpl.OpGenerator}.
 * This operation is added to the list of pending actions during {@link #commit()}, and
 * will be executed on the UI thread to run this FragmentTransaction.
 */
@Override
public boolean generateOps(ArrayList<BackStackRecord> records, ArrayList<Boolean> isRecordPop) {
    if (FragmentManagerImpl.DEBUG) {
        Log.v(TAG, "Run: " + this);
    }

    records.add(this);//將自身加入mTmpRecords。
    isRecordPop.add(false);
    if (mAddToBackStack) {
        mManager.addBackStackState(this);//事務加入返回棧
    }
    return true;
}

FragmentManagerImpl:

private class PopBackStackState implements OpGenerator {
    @Override
    public boolean generateOps(ArrayList<BackStackRecord> records,
            ArrayList<Boolean> isRecordPop) {
        return popBackStackState(records, isRecordPop, mName, mId, mFlags);
    }
}

@SuppressWarnings("unused")
boolean popBackStackState(ArrayList<BackStackRecord> records, ArrayList<Boolean> isRecordPop,
        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;
        }
        records.add(mBackStack.remove(last));//取出返回棧中事務加入mTmpRecords。
        isRecordPop.add(true);
    } else {
        ......
    }
    return true;
}

總結

事務提交(無論事務是否進棧)和事務出棧的不同之處在於enqueueAction()時傳入的入參不同。
事務提交:mManager.enqueueAction(this, allowStateLoss); 注:this是BackStackRecord。
事務出棧:enqueueAction(new PopBackStackState(null, -1, 0), false);

新增action到mPendingActions 之後,後續流程是一樣的。

關鍵:
1. 結構:理解Fragment 處理事務的結構,該結構由mTmpRecords 和 mBackStack 這兩個事務列表組成。
1. 更新fragment 列表:同時,還要意識到,每個Op 操作後都會更新mAdded 和mActive 這兩個fragment 列表。
1. 切換生命週期:最後都只是對mAdded 和mActive 中的所有fragment 進行生命週期的切換。

Fragment返回棧原理

相關推薦

原始碼解析Fragment 返回原理

事務提交 流程 原始碼 事務出棧 流程 原始碼 總結 返回棧涉及的類 在看本文前需要熟悉Fragment 的使用,不清楚的可先看:Fragment使用詳解 本文原始碼都是都是v25 的support v4 包下的原始碼。

Fragment返回的手動管理

如何回到上一個Fragment 專案開中需要經常在不同的Fragment之間跳轉,隨時可能從一個Fragment頁面跳到另一個Fragment頁面。 這些頁面的切換還是比較簡單的,根據業務需求,相應地呼叫FragmentTransaction的show()、ad

原始碼解析之HashMap實現原理

目錄 二,栗子 一,寫在前面 在日常開發中,HashMap因其可以儲存鍵值對的特點經常被使用,僅僅知道如何使用HashMap是遠遠不夠的。以知其然知其所以然的鑽研態度,本篇文章將以圖文,原始碼的方式去解析HashMap的實現原理。 二,栗子

透過 NestedScrollView 原始碼解析巢狀滑動原理

NestedScrollView 是用於替代 ScrollView 來解決巢狀滑動過程中的滑動事件的衝突。作為開發者,你會發現很多地方會用到巢狀滑動的邏輯,比如下拉重新整理頁面,京東或者淘寶的各種商品頁面。 那為什麼要去了解 NestedScrollView 的原始碼呢?那是因為 Nest

CopyOnWriteArrayList實現原理以及原始碼解析

CopyOnWriteArrayList實現原理以及原始碼解析 1、CopyOnWrite容器(併發容器) Copy-On-Write簡稱COW,是一種用於程式設計中的優化策略。 其基本思路是,從一開始大家都在共享同一個內容,當某個人想要修改這個內容的時候,才

LinkedList實現原理以及原始碼解析(1.7)

LinkedList實現原理以及原始碼解析(1.7) 在1.7之後,oracle將LinkedList做了一些優化, 將1.6中的環形結構優化為了直線型了連結串列結構。 1、LinkedList定義: public class LinkedList<E>

ArrayList實現原理以及原始碼解析(補充JDK1.7,1.8)

ArrayList實現原理以及原始碼解析(補充JDK1.7,1.8) ArrayList的基本知識在上一節已經討論過,這節主要看ArrayList在JDK1.6到1.8的一些實現變化。 JDK版本不一樣,ArrayList類的原始碼也不一樣。 1、ArrayList類結構:

ArrayList實現原理以及原始碼解析(JDK1.6)

ArrayList實現原理以及原始碼解析(JDK1.6) 1、ArrayList ArrayList是基於陣列實現的,是一個動態陣列,其容量能自動增長,類似於C語言中的動態申請記憶體,動態增長記憶體。 ArrayList不是執行緒安全的,只能用在單執行緒環境下。

ConcurrentHashMap實現原理以及原始碼解析

ConcurrentHashMap實現原理以及原始碼解析 ConcurrentHashMap是Java1.5中引用的一個執行緒安全的支援高併發的HashMap集合類。 1、執行緒不安全的HashMap 因為多執行緒環境下,使用Hashmap進行put操作會引起死迴圈

Spring原始碼解析(十六)——AOP原理——獲取攔截器鏈——MethodInterceptor

   *     3)、目標方法執行    ;  *         容器中儲存了元件的代理物件(cglib增強後的物件),這個物件裡面儲存了詳細

Spring原始碼解析(十五)——AOP原理——建立aop代理

   * AnnotationAwareAspectJAutoProxyCreator【InstantiationAwareBeanPostProcessor】    的作用:  * 1)、每一個bean建立之前,呼叫postProce

Spring原始碼解析(十四)——AOP原理——AnnotationAwareAspectJAutoProxyCreator執行時機

     *             AnnotationAwareAspectJAutoProxyCreator => InstantiationAwareBean

Spring原始碼解析(十三)——AOP原理——AnnotationAwareAspectJAutoProxyCreator註冊

 * 2、 AnnotationAwareAspectJAutoProxyCreator:  *         AnnotationAwareAspectJAutoProxyCreator &nbs

Spring原始碼解析(十二)——AOP原理——@EnableAspectJAutoProxy

一、@EnableAspectJAutoProxy 第一步:註冊AnnotationAwareAspectJAutoProxyCreator 把AnnotationAwareAspectJAutoProxyCreator建立為RootBeanDefinition,加入

Spring原始碼解析(十一)——AOP原理——demo

1.業務類 public class MathCalculator { public int div(int i, int j) { System.out.println("MathCalculator---div"); return i / j;

CocurrentHashMap實現原理原始碼解析

##1、CocurrentHashMap概念      CocurrentHashMap是jdk中的容器,是hashmap的一個提升,結構圖: 這裡對比在對比hashmap的結構: 可以看出CocurrentHashMap對比HashMa

List集合原始碼解析原理和用法

 注:以下所用原始碼均基於JDK1.8基礎(特殊說明除外) 先從原始碼入手解析: public interface List<E> extends Collection<E> {} An ordered collection (also know

機器學習實戰(Machine Learning in Action)學習筆記————03.決策樹原理原始碼解析及測試

機器學習實戰(Machine Learning in Action)學習筆記————03.決策樹原理、原始碼解析及測試關鍵字:決策樹、python、原始碼解析、測試作者:米倉山下時間:2018-10-24機器學習實戰(Machine Learning in Action,@author: Peter Harr

spring原始碼解析之AOP原理

一、準備工作   在這裡我先簡單記錄下如何實現一個aop: AOP:【動態代理】 指在程式執行期間動態的將某段程式碼切入到指定方法指定位置進行執行的程式設計方式; 1、匯入aop模組;Spring AOP:(spring-aspects) 2、定義一個業務邏輯類(

【NLP】Attention原理原始碼解析

對attention一直停留在淺層的理解,看了幾篇介紹思想及原理的文章,也沒實踐過,今天立個Flag,一天深入原理和原始碼!如果你也是處於attention model level one的狀態,那不妨好好看一下啦。 內容: 核心思想 原理解析(圖解+公式) 模型分類 優缺點 TF原始碼解析