Android 源码浅析:Fragment 生命周期、事务、回退栈、状态保存

lxf2023-05-04 00:52:43

前言

Fragment 应该是开发中使用频率较高的组件,在升级到 AndroidX 后源码也有一些更新,本文从生命周期、事务、回退栈、状态保存这四个角度来分析下其核心源码。

简单使用

val fragmentA = FragmentA()
val fragmentB = FragmentB()

val transaction = supportFragmentManager.beginTransaction()
transaction.add(R.id.container, fragmentA)
transaction.add(R.id.container, fragmentB)
transaction.hide(fragmentB)
transaction.show(fragmentA)
// transaction.replace(R.id.flContainer, FragmentC())
transaction.commit()

Fragment 生命周期

概览

Android 源码浅析:Fragment 生命周期、事务、回退栈、状态保存

官方给出的 Fragment 生命周期图,相信大家都已经烂熟于心就不多说了。

生命周期的触发

对于 Activity 来说其生命周期最终都是由 ActivityThread 的 mH (Handler)对象 sendMessage 来触发,而 Fragment 的生命周期则是依赖于它所依附的 Activity 来触发。

以 Activity 的 onCreate 为例,最终会调用到 FragmentActivity 的 onCreate 方法之中:

FragmentActivity.java

// FragmentController 是 Fragment 的大总管
// 初始化时传入的 HostCallbacks 继承自 FragmentHostCallback
// 内部包含了 FragmentManager 的实现类 FragmentManagerImpl
final FragmentController mFragments = FragmentController.createController(new HostCallbacks());

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) { 
    mFragments.attachHost(null);
    // ...
    super.onCreate(savedInstanceState);
    // ...
    
    // 调用 FragmentController 的 dispatchCreate
    mFragments.dispatchCreate();
}

FragmentController.java

public void dispatchCreate() {
    // mFragmentManager 就是 FragmentManagerImpl 的实例
    mHost.mFragmentManager.dispatchCreate();
}

FragmentManagerImpl.java

public void dispatchCreate() {
    mStateSaved = false;
    mStopped = false;
    // 最终调用了 dispatchStateChange
    dispatchStateChange(Fragment.CREATED);
}

其他的生命周期也是一样的,都是在 FragmentActivity 中 Activity 对应的生命周期中触发,最终交给 FragmentManagerImpl 来处理,其它 dispatchXXX 的最终也都是调用到了 dispatchStateChange 方法中。

FragmentManagerImpl.java

Android 源码浅析:Fragment 生命周期、事务、回退栈、状态保存

dispatchStateChange

先来看一下 dispatchStateChange 的参数都会传递哪些值:

Fragment.java

static final int INITIALIZING = 0;     
static final int CREATED = 1;         
static final int ACTIVITY_CREATED = 2; 
static final int STARTED = 3;          
static final int RESUMED = 4;

int mState = INITIALIZING; // Fragment 默认 state 是 INITIALIZING

这里相比于老版本少了一些 STOP、DESTORY 等等的状态标识,新版的设计只用这几个状态就够了,接下来看下 dispatchStateChange 是如何处理生命周期的。

private void dispatchStateChange(int nextState) {
    try {
        mExecutingActions = true;
        // 看名字就知道这里是更改状态的核心
        moveToState(nextState, false);
    } finally {
        mExecutingActions = false;
    }
    // 注意这里 后面事务小节会提到这个方法
    execPendingActions();
}

接着看下 moveToState 源码:

// 记录当前状态 默认 INITIALIZING
int mCurState = Fragment.INITIALIZING;
// 用 ArrayList 记录添加进来的 Fragment
final ArrayList<Fragment> mAdded = new ArrayList<>();

void moveToState(int newState, boolean always) {
    // ...
    // 最新状态赋值
    mCurState = newState;

    final int numAdded = mAdded.size();
    for (int i = 0; i < numAdded; i++) {
        Fragment f = mAdded.get(i);
        // 遍历调用 moveFragmentToExpectedState
        moveFragmentToExpectedState(f);
    }
    // ...
}

void moveFragmentToExpectedState(Fragment f) {
    // ...
    // 获取最新状态
    int nextState = mCurState;
    // ...
    // 又调用了 moveToState,这个和上面的 moveToState 不同,重载函数
    moveToState(f, nextState, f.getNextTransition(), f.getNextTransitionStyle(), false);
    // ...
}

注意最后的这个 moveToState 方法,这是接下来的重点,核心代码主要分为两个分支,这部分代码比较多,下面的源码把无关紧要的部分省略了,源码如下:

void moveToState(Fragment f, int newState, int transit, int transitionStyle,
                 boolean keepActive) {
    // ...
    // 注意 Fragment 默认状态是 INITIALIZING,dispatchOnCreate
    if (f.mState <= newState) {
        // ...
        // 注意这里的 switch 写法,每一个 case 分支中都没有写 break 关键字
        switch (f.mState) { // 默认值为 INITIALIZING
            case Fragment.INITIALIZING:
                // dispatchCreate 中传递过来的 newState 为 CREATE > INITIALIZING
                if (newState > Fragment.INITIALIZING) {
                    // 设置一些初始值等等 ...
                    // ...
                    if (!f.mIsCreated) {
                        // ...
                        // 这个方法里调用了 onAttach 生命周期方法
                        // 并且将 mState 设置为了 CREATED
                        f.performCreate(f.mSavedFragmentState);
                        // ...
                    }
                }
            case Fragment.CREATED:
                if (newState > Fragment.INITIALIZING) {
                    // 这里面依次调用了  f.performCreateView -> onCreateView
                    // f.onViewCreated
                    ensureInflatedFragmentView(f);
                }
                
                // 这个 if 需要在 Activity 进入 onStart 生命周期后调用 dispatchActivityCreated 进入
                if (newState > Fragment.CREATED) {
                    // ...
                    // 这里调用了 onActivityCreated 生命周期方法
                    // 并且 mState 设置为 ACTIVITY_CREATED
                    f.performActivityCreated(f.mSavedFragmentState);
                    // ...
                }
            case Fragment.ACTIVITY_CREATED:
                // 通过 dispatchStart 调用进入 if
                if (newState > Fragment.ACTIVITY_CREATED) {
                    // ...
                    // 内部调用了 onStart 生命周期,mState 设置为了 STARTED
                    f.performStart();
                    // ...
                }
            case Fragment.STARTED:
                if (newState > Fragment.STARTED) {
                    // ...
                    // 内部调用了 onResume 生命周期,mState 设置为了 RESUMED
                    f.performResume();
                    // ...
                }
        }
    } else if (f.mState > newState){
        // 这个 else if 分支就有意思了,Fragment 生命周期方法虽然有 onStop、onDsetory ...
        // 但是 mState 的值仅设计了 5 个,如果 newState < fragment.mState 则证明在走"销毁"的流程
        // 这里的"销毁"是指会走 onPause、onStop、onDestory 等生命周期
        switch (f.mState) {
            case Fragment.RESUMED:
                if (newState < Fragment.RESUMED) {
                    // ...
                    // 内部调用了 onPause 生命周期,mState 设置为了 STARTED
                    f.performPause();
                    // ...
                }
            case Fragment.STARTED:
                if (newState < Fragment.STARTED) {
                    // 内部调用了 onStop 生命周期,mState 设置为了 ACTIVITY_CREATED
                    f.performStop();
                }
            case Fragment.ACTIVITY_CREATED:
                if (newState < Fragment.ACTIVITY_CREATED) {
                    // ...
                    // 内部调用了 onDestoryView 生命周期,mState 设置为了 CREATED
                    f.performDestroyView();
                    // ...
                }
            case Fragment.CREATED:
                if (newState < Fragment.CREATED) {
                    // ...
                    // 等待动画执行完,仅将 newState 设置为 CREATED
                    if (f.getAnimatingAway() != null || f.getAnimator() != null) {
                        f.setStateAfterAnimating(newState);
                        newState = Fragment.CREATED;
                    } else {
                        // isInBackStack 是否在回退栈中
                        boolean beingRemoved = f.mRemoving && !f.isInBackStack();
                        if (beingRemoved || mNonConfig.shouldDestroy(f)) {
                            // ...
                            // 内部调用了 onDestory 生命周期,mState 设置为了 INITIALIZING
                            f.performDestroy();
                        } else { // 不论 if 还是 else 都将 mState 设置为了 INITIALIZING
                            f.mState = Fragment.INITIALIZING;
                        }
                        // 内部调用了 onDetach 生命周期
                        f.performDetach();
                        // ...
                    }
                }
        }
    }
}

上面的源码对于 if 分支来说比较容易理解,newState > mState 代表走正常初始化到可见的流程,而 newState < mState 则表示走 onResume 后面"销毁"相关的生命周期,来看一下这部分分发时的源码来理解下:

// 当 Fragment mState 处于 RESUMED 时,后续才会走 onPause 生命周期方法,此时分发的是 STARTED
// 而 STARTED < RESUMED 也就满足了 newState < mState
// 下面的类似
public void dispatchPause() {
    dispatchStateChange(Fragment.STARTED);
}

public void dispatchStop() {
    // ...
    dispatchStateChange(Fragment.ACTIVITY_CREATED);
}

public void dispatchDestroyView() {
    dispatchStateChange(Fragment.CREATED);
}

public void dispatchDestroy() {
    // ...
    dispatchStateChange(Fragment.INITIALIZING);
    // ...
}

这里再借用之前分析 Lifecycle 博客的一张图来帮助理解下:

Android 源码浅析:Fragment 生命周期、事务、回退栈、状态保存

Fragment 事务

很多博客讲解 Fragment 时都提到了事务,接下来再来分析一下到底什么是事务?如前面 “简单使用” 小节中的代码示例,通过 supportFragmentManager.beginTransaction() 开启事务,对其进行一系列操作后最终使用 commit() 提交事务。

那么先来看看,beginTransaction 的源码,看看其返回的是什么。supportFragmentManager 实际上就是 FragmentManagerImpl,其 beginTransaction 方法源码如下:

FragmentManagerImpl.java

public FragmentTransaction beginTransaction() {
    // 注意这里的参数 this,BackStackRecord 持有了 FragmentManagerImpl 实例
    return new BackStackRecord(this);
}

返回了一个 BackStackRecord 对象,其继承自抽象类 FragmentTransaction,后续的操作都是调用的 BackStackRecord,看下其 add 方法源码,add 在其父类中实现:

FragmentTransaction.java

public FragmentTransaction add(@IdRes int containerViewId, @NonNull Fragment fragment) {
    // 调用了 doAddOp
    doAddOp(containerViewId, fragment, null, OP_ADD);
    return this;
}

void doAddOp(int containerViewId, Fragment fragment, @Nullable String tag, int opcmd) {
    // ...
    // 调用了 addOp
    // 这里传入了一个 Op 对象 opcmd 值为 OP_ADD,并且持有了 fragment
    addOp(new Op(opcmd, fragment));
}

void addOp(Op op) {
    // mOps 是一个 ArrayList 成员变量
    mOps.add(op);
    // ...
}

事务的 add 方法相当于是将 Op 对象保存到了一个 ArrayList 中,那么再来看看除了 add 之外的其他操作:

public FragmentTransaction hide(@NonNull Fragment fragment) {
    addOp(new Op(OP_HIDE, fragment));
    return this;
}

public FragmentTransaction show(@NonNull Fragment fragment) {
    addOp(new Op(OP_SHOW, fragment));
    return this;
}

public FragmentTransaction replace(@IdRes int containerViewId, @NonNull Fragment fragment,
    // ...
    // replace 操作和 add 调用方法一样,但最后一个参数不同
    doAddOp(containerViewId, fragment, tag, OP_REPLACE);
    return this;
}

不难看出都是生成了一个 Op 对象添加到 ArrayList 中,看一下 Op 这个对象到底是什么:

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;
    // Op 是 FragmentTransaction 中的一个静态类
    static final class Op {
        int mCmd; // 操作命令
        Fragment mFragment; // fragment实例
        // 动画相关
        int mEnterAnim;
        int mExitAnim;
        int mPopEnterAnim;
        int mPopExitAnim;
        // ...
    }
    // 事务中的操作都保存在了这个 ArrayList 里
    ArrayList<Op> mOps = new ArrayList<>();
}

现在明白了事务中的操作并没有马上执行而是按顺序添加到了 ArrayList 中,那么肯定是在 commit() 方法中执行,接着看一下 commit() 的源码,commit() 是一个抽象方法由 BackStackRecord 实现:

BackStackRecord.java

final class BackStackRecord extends FragmentTransaction implements FragmentManager.BackStackEntry, FragmentManagerImpl.OpGenerator {
    // ...
    public int commit() {
        return commitInternal(false);
    }
    
    // 注意这里的 allowStateLoss,commit() 默认传递的 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 执行,别忘了在创建事务时传递的 this 参数
        // 这里的 mManager 就是 FragmentManagerImpl
        // 这里又将 BackStackRecord 本身传了进去
        mManager.enqueueAction(this, allowStateLoss);
        return mIndex;
    }
}

又回到了 FragmentManagerImpl 中,继续看其 enqueueAction 方法源码:

FragmentManagerImpl.java

// BackStackRecord 也实现了 OpGenerator 接口
public void enqueueAction(OpGenerator action, boolean allowStateLoss) {
    // ...
    synchronized (this) {
        // ...
        if (mPendingActions == null) {
            mPendingActions = new ArrayList<>();
        }
        // 添加到待执行的容器中 也是一个 ArrayList
        mPendingActions.add(action);
        // 执行提交
        scheduleCommit();
    }
}

void scheduleCommit() {
    synchronized (this) {
        boolean postponeReady = mPostponedTransactions != null && !mPostponedTransactions.isEmpty();
        // 上一步刚刚添加进去 所以这里为 true
        boolean pendingReady = mPendingActions != null && mPendingActions.size() == 1;
        if (postponeReady || pendingReady) {
            // 通过 Handler 执行 mExecCommit
            mHost.getHandler().removeCallbacks(mExecCommit);
            mHost.getHandler().post(mExecCommit);
            updateOnBackPressedCallbackEnabled();
        }
    }
}

// 这个 mExecCommit 中又调用了 execPendingActions
Runnable mExecCommit = new Runnable() {
    @Override
    public void run() {
        execPendingActions();
    }
};

到这里提一嘴,在前面的 dispatchStateChange 方法最后也执行了 execPendingAction。

execPendingAction

源码如下:

FragmentManagerImpl.java

ArrayList<BackStackRecord> mTmpRecords;
ArrayList<Boolean> mTmpIsPop;

public boolean execPendingActions() {
    // 里面初始化了 mTmpRecords、mTmpIsPop
    ensureExecReady(true);
    boolean didSomething = false;
    // 核心1 generateOpsForPendingActions
    while (generateOpsForPendingActions(mTmpRecords, mTmpIsPop)) {
        mExecutingActions = true;
        try {
            // 核心2 generateOpsForPendingActions
            removeRedundantOperationsAndExecute(mTmpRecords, mTmpIsPop);
        } finally {
            cleanupExec();
        }
        didSomething = true;
    }
    // ...
    return didSomething;
}

generateOpsForPendingActions

FragmentManagerImpl.java

private boolean generateOpsForPendingActions(ArrayList<BackStackRecord> records, ArrayList<Boolean> isPop) {
    boolean didSomething = false;
    synchronized (this) {
        // ...
        // mPendingActions 中存放的实际上就是 BackStackRecord
        final int numActions = mPendingActions.size();
        for (int i = 0; i < numActions; i++) {
            // 遍历执行 generateOps 方法
            didSomething |= mPendingActions.get(i).generateOps(records, isPop);
        }
        // 清空
        mPendingActions.clear();
        // 移除 Runnable
        mHost.getHandler().removeCallbacks(mExecCommit);
    }
    return didSomething;
}

这段代码核心就是遍历 mPendingActions 中的 BackStackRecord 对象执行其 generateOps 方法,注意这里传入的 records,isPop。

records 会存放 BackStackRecord 对象,而 isRecordPop 则是一个 ArrayList<Boolean> 用于标记 records 中的 BackStackRecord 对象是否有回退栈相关操作。

接着看其 generateOps 方法源码:

FragmentManagerImpl.java

final class BackStackRecord extends FragmentTransaction implements FragmentManager.BackStackEntry, FragmentManagerImpl.OpGenerator {
    // ...
    public boolean generateOps(ArrayList<BackStackRecord> records, ArrayList<Boolean> isRecordPop) {
        // ...
        records.add(this);
        // BackStackRecord 是没有回退栈操作的 直接设置为 false
        isRecordPop.add(false);
        // ...
        return true;
    }
    // ...
}

到这里为止仍然没有操作 Fragment,仅仅是将 BackStackRecord 有添加进了 mTmpRecords 中,并且用 mTmpIsPop 标记回退栈。

removeRedundantOperationsAndExecute

接着来看 removeRedundantOperationsAndExecute 源码:

FragmentManagerImpl.java

// 传入的两个参数是 mTmpRecords, mTmpIsPop
private void removeRedundantOperationsAndExecute(ArrayList<BackStackRecord> records, ArrayList<Boolean> 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) {
           // ...
           // 这里有一些优化,如: 先添加一个 Fragment 再移除 再添加 则只会执行最后一次添加的操作,前两次的操作属于无效操作
        }
    }
    if (startIndex != numRecords) {
        // 最终调用到了 executeOpsTogether
        // 参数分别对应 mTmpRecords, mTmpIsPop, startIndex 先当作是 0, numRecords 是 records 长度
        executeOpsTogether(records, isRecordPop, startIndex, numRecords);
    }
}

接着查看 executeOpsTogether 源码:

FragmentManagerImpl.java

private void executeOpsTogether(ArrayList<BackStackRecord> records, ArrayList<Boolean> isRecordPop, int startIndex, int endIndex) {
    // 默认 false
    final boolean allowReordering = records.get(startIndex).mReorderingAllowed;
    boolean addToBackStack = false;
    // 对 mTmpAddedFragments 初始化,如果已经初始化则清空
    if (mTmpAddedFragments == null) {
        mTmpAddedFragments = new ArrayList<>();
    } else {
        mTmpAddedFragments.clear();
    }
    // mAdded 前面说过,存放已经添加的 Fragment,赋值给 mTmpAddedFragments
    mTmpAddedFragments.addAll(mAdded);
    Fragment oldPrimaryNav = getPrimaryNavigationFragment();
    for (int recordNum = startIndex; recordNum < endIndex; recordNum++) {
        // 遍历取出 BackStackRecord
        final BackStackRecord record = records.get(recordNum);
        final boolean isPop = isRecordPop.get(recordNum);
        if (!isPop) { // 不执行回退栈相关操作
            // 执行到了其 expandOps 方法
            // 这个方法总的来说是处理每个 BackStackRecord 对象中的 mOps 
            // 重点
            oldPrimaryNav = record.expandOps(mTmpAddedFragments, oldPrimaryNav);
        } else { // 回退栈 后面讲
            oldPrimaryNav = record.trackAddedFragmentsInPop(mTmpAddedFragments, oldPrimaryNav);
        }
        addToBackStack = addToBackStack || record.mAddToBackStack;
    }
    // 执行完 record.expandOps 后清空临时容器
    mTmpAddedFragments.clear();
    // ...
    // 再这里之前全是一些状态、容器、一些标记的更新并没有正真操作 Fragment, 这里面是真正执行事务的操作
    // 重点
    executeOps(records, isRecordPop, startIndex, endIndex);
    // ...
}

record.expandOps

BackStackRecord.java

// added 参数是上一步的 mTmpAddedFragments
Fragment expandOps(ArrayList<Fragment> added, Fragment oldPrimaryNav) {
    for (int opNum = 0; opNum < mOps.size(); opNum++) {
        final Op op = mOps.get(opNum);
        switch (op.mCmd) {
            // add 和 attach 操作都直接将 fragment 添加进容器中
            case OP_ADD:
            case OP_ATTACH:
                added.add(op.mFragment);
                break;
            // remove 和 detach 操作直接从容器中移除
            case OP_REMOVE:
            case OP_DETACH: {
                added.remove(op.mFragment);
                // ...
            }
            break;
            // replace 操作稍微复杂些,如果 Fragment 没有在容器中则添加,如果已经存在则仅移除被替换的 Fragment
            // 被替换的 fragment 如果一样的话则仅移除之前的
            case OP_REPLACE: {
                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);
                    // 两个 fragment 的相同
                    if (old.mContainerId == containerId) {
                        if (old == f) {
                            alreadyAdded = true;
                        } else {
                            // ...
                            final Op removeOp = new Op(OP_REMOVE, old);
                            removeOp.mEnterAnim = op.mEnterAnim;
                            // ...
                            mOps.add(opNum, removeOp);
                            added.remove(old);
                            opNum++;
                        }
                    }
                }
                if (alreadyAdded) { // 已经添加
                    mOps.remove(opNum);
                    opNum--;
                } else { // 未添加
                    op.mCmd = OP_ADD;
                    added.add(f);
                }
            }
            break;
            // ...
        }
    }
    return oldPrimaryNav;
}

这里要注意下,replace 操作在 Op 对象中并没有对应的操作命令(mCmd变量的值),上述源码中将其分解为了 OP_ADD 和 OP_REMOVE 操作。

executeOps

FragmentManagerImpl.java

private static void executeOps(ArrayList<BackStackRecord> records, ArrayList<Boolean> isRecordPop, int startIndex, int endIndex) {
    // 遍历 records 执行其 executeOps 方法
    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);
            record.executePopOps(moveToState);
        } else { // 不是回退栈则执行 executeOps
            record.bumpBackStackNesting(1);
            record.executeOps();
        }
    }
}

继续查看 BackStackRecord 的 executeOps 方法源码:

BackStackRecord.java

void executeOps() {
    // 遍历 BackStackRecord 中的 mOps 对象
    final int numOps = mOps.size();
    for (int opNum = 0; opNum < numOps; opNum++) {
        final Op op = mOps.get(opNum);
        final Fragment f = op.mFragment;
        // ...
        // 根据 Op 对象的 mCmd 值执行对应操作
        // 以 ADD、MOVE、HIDE、SHOW 常见的操作为例 最终都调用到了 mManager 中
        // 也就是 FragmentManagerImpl 直到这里才算真正意义上的执行事务内容
        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;
            // ...
        }
        // ...
    }
    if (!mReorderingAllowed) {
        // 最后又回到了 moveToState 方法
        mManager.moveToState(mManager.mCurState, true);
    }
}

再以上述 OP_ADD 命令为例,看下具体的操作:

FragmentManagerImpl.java

// 假设当前 moveToStateNow 为 false
public void addFragment(Fragment fragment, boolean moveToStateNow) {
    // 先将 fragment 设置为激活状态,也就是放入 mActive 容器中
    makeActive(fragment);
    if (!fragment.mDetached) {
        // ...
        // 添加到 mAdded 容器中
        synchronized (mAdded) {
            mAdded.add(fragment);
        }
        // 修改一些状态值
        fragment.mAdded = true;
        fragment.mRemoving = false;
        if (fragment.mView == null) {
            fragment.mHiddenChanged = false;
        }
        if (isMenuAvailable(fragment)) {
            mNeedMenuInvalidate = true;
        }
        // false 不会执行
        if (moveToStateNow) {
            moveToState(fragment);
        }
    }
}

其他方法也类似,都是改变 Fragment 的一些状态值,篇幅原因就不贴源码了。

由此可见,事务的本质是修改对应 Fragment 的一些状态值,通过 FragmentManagerImpl 对 Fragment 进行管理,最终依然通过 moveToState 来调度 Fragment。

回退栈

在使用事务时,我们也可以调用其 addToBackStack 方法将其加入至回退栈,后续可以使用 popBackStack 方法使其达到类似于 Activity 回退栈的效果:

val transaction = supportFragmentManager.beginTransaction()
// 省略操作...
transaction.addToBackStack(null)
transaction.commit()

// 返回上一回退栈
supportFragmentManager.popBackStack()

在之前小节源码中也不止一次看到关于回退栈的分支部分,接下来就来简单分析下 AndroidX 中 Fragment 是如何实现回退栈的。

addToBackStack

先来看下 addToBackStack 到底做了什么事情:

FragmentTransaction.java

public FragmentTransaction addToBackStack(@Nullable String name) {
    // ...
    // 仅仅改变了 mAddToBackStack 变量为 true
    mAddToBackStack = true;
    mName = name;
    return this;
}

mAddToBackStack 在上面 commit 源码分析中有提到过,再次查看 commit 流程中的源码:

BackStackRecord.java

int commitInternal(boolean allowStateLoss) {
    // ...
    if (mAddToBackStack) {
        // 会额外执行一次 allocBackStackIndex 方法
        // 并且获得索引 赋值给 mIndex
        mIndex = mManager.allocBackStackIndex(this);
    } else {
        mIndex = -1;
    }
    mManager.enqueueAction(this, allowStateLoss);
    return mIndex;
}

接着查看 allocBackStackIndex 源码:

FragmentManagerImpl.java

// allocBackStackIndex 用到的两个变量
ArrayList<BackStackRecord> mBackStackIndices; // 调用过 addToBackStack 的 BackStackRecord 对象都会存放进去
ArrayList<Integer> mAvailBackStackIndices; // mBackStackIndices 索引

public int allocBackStackIndex(BackStackRecord bse) {
    synchronized (this) {
        // 默认会进入这个 if
        if (mAvailBackStackIndices == null || mAvailBackStackIndices.size() <= 0) {
            // 初始化
            if (mBackStackIndices == null) {
                mBackStackIndices = new ArrayList<BackStackRecord>();
            }
            // 将 BackStackRecord 添加进去
            int index = mBackStackIndices.size();
            mBackStackIndices.add(bse);
            return index;
        } else { // 当 mAvailBackStackIndices 不为空时进入
            // 获取索引 将 BackStackRecord 添加到 指定位置
            int index = mAvailBackStackIndices.remove(mAvailBackStackIndices.size()-1);
            mBackStackIndices.set(index, bse);
            return index;
        }
    }
}

这么看这段代码有点懵,光看这里的代码片段感觉不出 mAvailBackStackIndices 有什么用,再来看一个方法:

FragmentManagerImpl.java

// 看名字大概是 释放 BackStackRecord 对象
public void freeBackStackIndex(int index) {
    synchronized (this) {
        // 从容器中移除
        mBackStackIndices.set(index, null);
        // 初始化
        if (mAvailBackStackIndices == null) {
            mAvailBackStackIndices = new ArrayList<Integer>();
        }
        // 记录 mBackStackIndices 中置空的索引
        mAvailBackStackIndices.add(index);
    }
}

结合到一起看很容易就理解了,mBackStackIndices 中的对象会被移除,在移除时记录索引,下次再添加时优先往数组中置空的位置添加,这样可以有效的防止内存碎片。

commit 后面的流程中在遍历执行 BackStackRecord 对象的 generateOps 方法中也有一处关于 mAddToBackStack 的判断:

BackStackRecord.java

public boolean generateOps(ArrayList<BackStackRecord> records, ArrayList<Boolean> isRecordPop) {
    // ...
    if (mAddToBackStack) {
        mManager.addBackStackState(this);
    }
    return true;
}

FragmentManagerImpl.java

ArrayList<BackStackRecord> mBackStack;

void addBackStackState(BackStackRecord state) {
    if (mBackStack == null) {
        mBackStack = new ArrayList<BackStackRecord>();
    }
    mBackStack.add(state);
}

总的来说调用 addToBackStack 加入回退栈后,本次事务的 BackStackRecord 对象会被保存进 mBackStack 中,并且通过 mBackStackIndices 获得索引。

popBackStack

从上一小节得知加入回退栈相当于将本次事务对象添加进 mBackStackIndices 容器中,那么看看回退时是如何使用的:

public void popBackStack() {
    // 这个方法是不是非常眼熟,再 commit 流程中也是调用了 enqueueAction
    // 只不过 commit 传入的是 BackStackRecord 对象
    // 而这里传入的是 PopBackStackState 
    // 这里会将其添加到 mPendingActions 中
    enqueueAction(new PopBackStackState(null, -1, 0), false);
}

enqueueAction 后面的流程上面都说过了就直接跳过,直接看重点部分,遍历执行 mPendingActions:

private boolean generateOpsForPendingActions(ArrayList<BackStackRecord> records, rrayList<Boolean> isPop) {
    // ...
    for (int i = 0; i < numActions; i++) {
        didSomething |= mPendingActions.get(i).generateOps(records, isPop);
    }
    // ...
}

这里就调用到了 PopBackStackState 中的 generateOps:

PopBackStackState.java

public boolean generateOps(ArrayList<BackStackRecord> records,
                           ArrayList<Boolean> isRecordPop) {
    // ...
    return popBackStackState(records, isRecordPop, mName, mId, mFlags);
}

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;
        }
        // 这行代码是核心,从 mBackStack 中移除最后一个
        // 将其添加到 records 中
        records.add(mBackStack.remove(last));
        // isRecordPop 也改为 true
        isRecordPop.add(true);
    } else {
        // else 中是根据 name 寻找的逻辑 就不贴了
        // ...
    }
    return true;
}

这部分主要记住两点:

  1. 从 mBackStack 中取出最后一个元素将其添加到 records 中;
  2. isRecordPop 对应的位置添加 true 元素;

前面的 commit 流程小节中还有两处关于回退栈的方法 executeOpsTogetherexecuteOps,分别再来看下这两个方法对应部分:

FragmentManagerImpl.java

private void executeOpsTogether(ArrayList<BackStackRecord> records, ArrayList<Boolean> isRecordPop, int startIndex, int endIndex) {
    // ...
    for (int recordNum = startIndex; recordNum < endIndex; recordNum++) {
        final BackStackRecord record = records.get(recordNum);
        final boolean isPop = isRecordPop.get(recordNum); // 这里为 true
        if (!isPop) {
            oldPrimaryNav = record.expandOps(mTmpAddedFragments, oldPrimaryNav);
        } else { // 调用到了 trackAddedFragmentsInPop 中
            oldPrimaryNav = record.trackAddedFragmentsInPop(mTmpAddedFragments, oldPrimaryNav);
        }
    }
    // ...
}

这里就和 if 中的 expandOps 不同了: BackStackRecord.java

Fragment trackAddedFragmentsInPop(ArrayList<Fragment> added, Fragment oldPrimaryNav) {
    for (int opNum = mOps.size() - 1; opNum >= 0; opNum--) {
        final Op op = mOps.get(opNum);
        switch (op.mCmd) {
            case OP_ADD:
            case OP_ATTACH: // add 和 attach 分支调用了 remove
                added.remove(op.mFragment);
                break;
            case OP_REMOVE:
            case OP_DETACH: // remove 和 detach 分支调用了 add
                added.add(op.mFragment);
                break;
            // ...
        }
    }
    // ...
}

这里也不难理解,既然是回退栈肯定是跟当前操作是反着的。接着再来看看 executeOps 方法中关于回退栈的部分:

FragmentManagerImpl.java

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) { // true
            record.bumpBackStackNesting(-1);
            // 执行到最后一次循环时为 true
            boolean moveToState = i == (endIndex - 1);
            // 调用了 executePopOps 方法
            record.executePopOps(moveToState);
        } else {
            record.bumpBackStackNesting(1);
            record.executeOps();
        }
    }
}

接着看看 executePopOps 方法:

void executePopOps(boolean moveToState) {
    for (int opNum = mOps.size() - 1; opNum >= 0; opNum--) {
        // ...
        // 不出意外 switch 中的分支和 executeOps 中方法是反着的
        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;
            // ...
    }
    // moveToState 为 true 时调用 moveToState 触发对应的生命周期方法
    if (!mReorderingAllowed && moveToState) {
        mManager.moveToState(mManager.mCurState, true);
    }
}

这里稍微总结一下,回退栈的实现就是将事务对象 BackStackRecord 进行保存,在回退时取出执行,后面和 commit 的主要流程是相似的。

状态保存与恢复

和 Activity 一样,Fragment 也可以进行状态的保存,不过也是依赖于 Activity 的,接下来来看一下 Fragment 是如何实现状态保存与恢复的。

保存

直接看 FragmentActivity 中的 onSaveInstanceState 方法:

FragmentActivity.java

static final String FRAGMENTS_TAG = "android:support:fragments";

protected void onSaveInstanceState(@NonNull Bundle outState) {
    // ...
    Parcelable p = mFragments.saveAllState();
    if (p != null) {
        outState.putParcelable(FRAGMENTS_TAG, p);
    }
    // ...
}

可以看出调用了 FragmentController 的 saveAllState 获取数据进行了保存,看一下 saveAllState 是如何保存的:

public Parcelable saveAllState() {
    return mHost.mFragmentManager.saveAllState();
}

又调用到了 FragmentManagerImpl 中:

Parcelable saveAllState() {
    // ...
    // mActive 为空就跳过
    if (mActive.isEmpty()) {
        return null;
    }
    int size = mActive.size();
    // FragmentState 容器
    ArrayList<FragmentState> active = new ArrayList<>(size);
    boolean haveFragments = false;
    // 遍历
    for (Fragment f : mActive.values()) {
        if (f != null) {
            // ...
            // 新建 FragmentState
            FragmentState fs = new FragmentState(f);
            // 添加进容器 
            active.add(fs);
            if (f.mState > Fragment.INITIALIZING && fs.mSavedFragmentState == null) {
                // 下面这部分全是对 FragmentState 的赋值操作 就省略了
                fs.mSavedFragmentState = saveFragmentBasicState(f);
                // ...
        }
    }
    // ...
    ArrayList<String> added = null; // 保存已经添加的 Fragment
    BackStackState[] backStack = null; // 用于保存回退栈
    size = mAdded.size();
    if (size > 0) {
        added = new ArrayList<>(size); // 初始化
        for (Fragment f : mAdded) { // 遍历添加进去
            added.add(f.mWho);
            // ...
        }
    }
    // 回退栈容器不为空
    if (mBackStack != null) {
        size = mBackStack.size();
        if (size > 0) {
            backStack = new BackStackState[size];
            for (int i = 0; i < size; i++) { // 遍历添加进去
                backStack[i] = new BackStackState(mBackStack.get(i));
                // ...
            }
        }
    }
    // 又创建了 FragmentManagerState
    FragmentManagerState fms = new FragmentManagerState();
    fms.mActive = active; // FragmentState 集合
    fms.mAdded = added; // Fragemnt 集合
    fms.mBackStack = backStack; // 回退栈集合
    // ...
    return fms;
}

可以看出 Fragment 状态保存是通过 FragmentManagerState,相关的信息都存储到了其中,再交由 Activity 进行保存。

恢复

恢复部分同样从 FragmentActivity 中入手查看源码:

protected void onCreate(@Nullable Bundle savedInstanceState) {
    // ...
    if (savedInstanceState != null) {
        Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);
        mFragments.restoreSaveState(p);
    }
    // ...
}

在 Activity onCreate 中将存储的信息取出交给 FragmentController 处理,继续查看 restoreSaveState 源码:

public void restoreSaveState(@Nullable Parcelable state) {
    // ...
    mHost.mFragmentManager.restoreSaveState(state);
}

同样交给了 FragementManagerImpl 来处理:

void restoreSaveState(Parcelable state) {
    if (state == null) return;
    // 强转
    FragmentManagerState fms = (FragmentManagerState)state;
    if (fms.mActive == null) return;
    // ...
    mActive.clear();
    // 从 FragmentManagerState 中获取 FragmentState
    for (FragmentState fs : fms.mActive) {
        // 相关赋值操作
        if (fs != null) {
            Fragment f = fs.instantiate(mHost.getContext().getClassLoader(),
                    getFragmentFactory());
            f.mFragmentManager = this;
            mActive.put(f.mWho, f);
            fs.mInstance = null;
        }
    }

    mAdded.clear();
    if (fms.mAdded != null) {
        // 将 fms 中的 mAdded 赋值给 FragmentManagerImpl 中的 mAdded
        for (String who : fms.mAdded) {
            Fragment f = mActive.get(who);
            if (f == null) {
                throwException(new IllegalStateException("No instantiated fragment for (" + who + ")"));
            }
            f.mAdded = true; // 标记
            if (mAdded.contains(f)) {
                throw new IllegalStateException("Already added " + f);
            }
            synchronized (mAdded) {
                mAdded.add(f); // 添加
            }
        }
    }

    if (fms.mBackStack != null) {
        mBackStack = new ArrayList<BackStackRecord>(fms.mBackStack.length);
        for (int i=0; i<fms.mBackStack.length; i++) {
            BackStackRecord bse = fms.mBackStack[i].instantiate(this);
            // 恢复 mBackStack 回退栈
            mBackStack.add(bse);
            if (bse.mIndex >= 0) {
                // 恢复 mBackStackIndices 索引表
                setBackStackIndex(bse.mIndex, bse);
            }
        }
    }
    // ...
}

总结

  1. Fragment 生命周期触发始于 Activity,对应生命周期触发后通过 FragmentManagerImpl 的 moveToState 方法调度 Fragment生命周期方法;
  2. Fragment 事务执行的本质是生成 BackStackRecord 对象,add、remove、replace 等操作会向其添加 Op 对象,最终通过遍历执行 Op 对象的“命令” 调用 FragmentManagerImpl 中对应的方法;
  3. 回退栈原理就是保存执行事务时生成的 BackStackRecord 对象;
  4. 状态保存(和恢复)依赖于 Activity,会生成 FragmentManagerState 对象保存相关数据;

最后

Fragment 还有很多细节没有说到,比如:提交时的四个方法(commitcommitNowcommitAllowingStateLosscommitNowAllowingStateLoss),popBackStack 也同样有 popBackStackImmediate 和其他重载方法。不过了解了最 Fragment 核心的原理,这些部分的源码阅读起来也就没那么困难了。