Overall process
In the previous article, I analyzed the fragment life cycle process from the perspectives of activity and fragment itself. Interested partners can go and analyze the fragment life cycle process from the perspective of source code . Here is a flowchart of add to see. It is more intuitive, and it will also mention which steps add and replace are different.
add and replace
The main difference between add and replace in the source code is mentioned in
- It must be that the original op.mCmd values of add and replace are different, one is OP_ADD and the other is OP_REPLACE
- The replace in the record.expandOps method will split OP_REPLACE into OP_REMOVE and OP_ADD and then execute fragmentStateManager.moveToExpectedState() in a loop; the difference is here, replace has an additional remove operation, which will remove the previous fragment. The life cycle of the removed fragment goes to onDestroyView or onDetach to see if its transaction is added to the return stack, see the third point for details
- The expected life cycle obtained by the computeExpectedState method is different
// fragmentStateManager
int computeExpectedState() {
//mFragmentManagerState的值来源于创建fragmentStateManager的时候,把fragmentManager的生命周期赋值给它
int maxState = mFragmentManagerState;
//这个是和fragmentTransaction.setMaxLifecycle配合使用的,这里没用到,默认是RESUMED
switch (mFragment.mMaxState) {
case RESUMED:
// maxState can't go any higher than RESUMED, so there's nothing to do here
break;
case STARTED:
maxState = Math.min(maxState, Fragment.STARTED);
break;
case CREATED:
maxState = Math.min(maxState, Fragment.CREATED);
break;
case INITIALIZED:
maxState = Math.min(maxState, Fragment.ATTACHED);
break;
default:
maxState = Math.min(maxState, Fragment.INITIALIZING);
}
//这里貌似是判断是否在xml中引入的fragment
if (mFragment.mFromLayout) {
if (mFragment.mInLayout) {
// Move them immediately to VIEW_CREATED when they are
// actually added to the layout (mInLayout).
maxState = Math.max(mFragmentManagerState, Fragment.VIEW_CREATED);
// But don't move to higher than VIEW_CREATED until the view is added to its parent
// and the LayoutInflater call has returned
if (mFragment.mView != null && mFragment.mView.getParent() == null) {
maxState = Math.min(maxState, Fragment.VIEW_CREATED);
}
} else {
if (mFragmentManagerState < Fragment.ACTIVITY_CREATED) {
// But while they are not in the layout, don't allow their
// state to progress upward until the FragmentManager state
// is at least ACTIVITY_CREATED. This ensures they get the onInflate()
// callback before being attached or created.
maxState = Math.min(maxState, mFragment.mState);
} else {
// Once the FragmentManager state is at least ACTIVITY_CREATED
// their state can progress up to CREATED as we assume that
// they are not ever going to be in layout
maxState = Math.min(maxState, Fragment.CREATED);
}
}
}
//如果是add提交事务的话就走不进该判断,而replace由于被拆分成remove和add
//remove操作在executeOps方法removeFragment的时候就置为false了
//因此此时add操作:maxState==RESUMED,remove操作:masState==CREATED
if (!mFragment.mAdded) {
maxState = Math.min(maxState, Fragment.CREATED);
}
if (awaitingEffect == SpecialEffectsController.Operation.LifecycleImpact.ADDING) {
// Fragments awaiting their enter effects cannot proceed beyond that state
maxState = Math.min(maxState, Fragment.AWAITING_ENTER_EFFECTS);
} else if (awaitingEffect == SpecialEffectsController.Operation.LifecycleImpact.REMOVING) {
// Fragments that are in the process of being removed shouldn't go below that state
maxState = Math.max(maxState, Fragment.AWAITING_EXIT_EFFECTS);
}
//这里也是同样的道理executeOps方法removeFragment的时候mRemoving会被置为true
else if (mFragment.mRemoving) {
//被replace的fragment是否加入了返回栈,加入了maxState==CREATED,否则为INITIALIZING
if (mFragment.isInBackStack()) {
// Fragments on the back stack shouldn't go higher than CREATED
maxState = Math.min(maxState, Fragment.CREATED);
} else {
// While removing a fragment, we always move to INITIALIZING
maxState = Math.min(maxState, Fragment.INITIALIZING);
}
}
return maxState;
}
//moveToExpectedState方法
//通过上面可以知道remove操作得到的期望的生命周期肯定小于当前的生命周期状态,这个时候和add就是完全想反的操作了
//以下代码解释了为什么加入返回栈的只会走到onDestroyView,而未加入的会走detach
case Fragment.CREATED:
destroyFragmentView();
mFragment.mState = Fragment.CREATED;
break;
case Fragment.ATTACHED:
destroy();
break;
case Fragment.INITIALIZING:
detach();
break;
fragment return stack
what addToBackStack does
public FragmentTransaction addToBackStack(@Nullable String name) {
if (!mAllowAddToBackStack) {
throw new IllegalStateException(
"This FragmentTransaction is not allowed to be added to the back stack.");
}
//这里呼应了BackStackRecord的generateOps,会把事务加入到fragmentManager的mBackStack列表中
mAddToBackStack = true;
//这是我们自己设置的名字,可以为null
mName = name;
return this;
}
what popBackStack does
Here is the simplest fragmentManager.popBackStack() to discuss
public void popBackStack() {
//很熟悉的方法enqueueAction,也是向列表中提交事务,不过这里实例化了一个PopBackStackState对象,有必要看一下
enqueueAction(new PopBackStackState(null, -1, 0), false);
}
private class PopBackStackState implements OpGenerator {
final String mName;
final int mId;
final int mFlags;
//PopBackStackState也实现了OpGenerator接口,目前name==null,id==-1,flag==0
PopBackStackState(@Nullable String name, int id, int flags) {
mName = name;
mId = id;
mFlags = flags;
}
}
At present, the actions constructed by popBackStack and add and replace are different. One is BackStackRecord and the other is PopBackStackState.
After the construction is completed, actions are put into the fragmentManager's queue and executed. The source of the transaction is different, and the generateOps is of course different. This part of the flow chart is echoed here:
Take a look at generateOps in PopBackStackState
@Override
public boolean generateOps(@NonNull ArrayList<BackStackRecord> records,
@NonNull ArrayList<Boolean> isRecordPop) {
//已省略...
//目前name==null,id==-1,flag==0
return popBackStackState(records, isRecordPop, mName, mId, mFlags);
}
The core is popBackStackState now let's take a look
@SuppressWarnings({"unused", "WeakerAccess"}) /* synthetic access */
boolean popBackStackState(@NonNull ArrayList<BackStackRecord> records,
@NonNull ArrayList<Boolean> isRecordPop, @Nullable String name, int id, int flags) {
if (mBackStack == null) {
return false;
}
//由于目前name==null,id==-1,flag==0所以会直接进入if的判断中
if (name == null && id < 0 && (flags & POP_BACK_STACK_INCLUSIVE) == 0) {
//这里直接把返回栈的最后一个数据放入records列表中并且isRecordPop的数据也为true
int last = mBackStack.size() - 1;
if (last < 0) {
return false;
}
//需要注意这里保存的数据是之前提交的事务
records.add(mBackStack.remove(last));
isRecordPop.add(true);
} else {
int index = -1;
if (name != null || id >= 0) {
// If a name or ID is specified, look for that place in
// the stack.
index = mBackStack.size() - 1;
while (index >= 0) {
BackStackRecord bss = mBackStack.get(index);
if (name != null && name.equals(bss.getName())) {
break;
}
if (id >= 0 && id == bss.mIndex) {
break;
}
index--;
}
if (index < 0) {
return false;
}
if ((flags & POP_BACK_STACK_INCLUSIVE) != 0) {
index--;
// Consume all following entries that match.
while (index >= 0) {
BackStackRecord bss = mBackStack.get(index);
if ((name != null && name.equals(bss.getName()))
|| (id >= 0 && id == bss.mIndex)) {
index--;
continue;
}
break;
}
}
}
if (index == mBackStack.size() - 1) {
return false;
}
for (int i = mBackStack.size() - 1; i > index; i--) {
records.add(mBackStack.remove(i));
isRecordPop.add(true);
}
}
return true;
}
So far, the data for the popBackStack() method has been constructed, and the following process is continued:
In the executeOps method, it will determine whether it is popped from the stack. If so, execute the executePopOps method:
//BackStackRecord
//可以看出这里是和当前事务执行相反的操作,比如之前的事务的操作是OP_ADD
//这里判断到是case OP_ADD时是执行remove操作
void executePopOps(boolean moveToState) {
for (int opNum = mOps.size() - 1; opNum >= 0; opNum--) {
final Op op = mOps.get(opNum);
Fragment f = op.mFragment;
if (f != null) {
f.setPopDirection(true);
f.setNextTransition(FragmentManager.reverseTransit(mTransition));
// Reverse the target and source names for pop operations
f.setSharedElementNames(mSharedElementTargetNames, mSharedElementSourceNames);
}
switch (op.mCmd) {
case OP_ADD:
f.setAnimations(op.mEnterAnim, op.mExitAnim, op.mPopEnterAnim, op.mPopExitAnim);
mManager.setExitAnimationOrder(f, true);
mManager.removeFragment(f);
break;
case OP_REMOVE:
f.setAnimations(op.mEnterAnim, op.mExitAnim, op.mPopEnterAnim, op.mPopExitAnim);
mManager.addFragment(f);
break;
case OP_HIDE:
f.setAnimations(op.mEnterAnim, op.mExitAnim, op.mPopEnterAnim, op.mPopExitAnim);
mManager.showFragment(f);
break;
When executeOps is executed, all preparations are over, and the subsequent operations are the same as add. The fragment is moved to the desired life cycle state through moveToExpectedState.
The popBackStack series of methods will call popBackStackState to construct
records
andisRecordPop
list,isRecordPop
and the values of the internal elements are all true. The subsequent process is the same as the commit transaction, andisRecordPop
theexecutePopOps
orexecuteOps
method is selected according to the different value.
A final summary: for popBackStack(String name, int flag), the name is the parameter of addToBackStack(String name), if you only call popBackStack(), the name is null, and the flag is 0, the specific element of the back stack can be found by name, flag Can be 0. Alternatively
FragmentManager.POP_BACK_STACK_INCLUSIVE
, 0 means that only all elements above this element are popped, and all elementsPOP_BACK_STACK_INCLUSIVE
that contain this element and above are popped. Popping all elements mentioned here includes rolling back these transactions. For details, please refer to the source code in the popBackStackState method.