前言
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 生命周期
概览
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 生命周期图,相信大家都已经烂熟于心就不多说了。
生命周期的触发
对于 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
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 博客的一张图来帮助理解下:
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;
}
这部分主要记住两点:
- 从 mBackStack 中取出最后一个元素将其添加到 records 中;
- isRecordPop 对应的位置添加 true 元素;
前面的 commit 流程小节中还有两处关于回退栈的方法 executeOpsTogether
和 executeOps
,分别再来看下这两个方法对应部分:
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);
}
}
}
// ...
}
总结
- Fragment 生命周期触发始于 Activity,对应生命周期触发后通过 FragmentManagerImpl 的 moveToState 方法调度 Fragment生命周期方法;
- Fragment 事务执行的本质是生成 BackStackRecord 对象,add、remove、replace 等操作会向其添加 Op 对象,最终通过遍历执行 Op 对象的“命令” 调用 FragmentManagerImpl 中对应的方法;
- 回退栈原理就是保存执行事务时生成的 BackStackRecord 对象;
- 状态保存(和恢复)依赖于 Activity,会生成 FragmentManagerState 对象保存相关数据;
最后
Fragment 还有很多细节没有说到,比如:提交时的四个方法(commit
、commitNow
、commitAllowingStateLoss
、commitNowAllowingStateLoss
),popBackStack
也同样有 popBackStackImmediate
和其他重载方法。不过了解了最 Fragment 核心的原理,这些部分的源码阅读起来也就没那么困难了。