fragment基本操作:
getSupportFragmentManager().beginTransaction()
.add(id, fragment, tag)
.addToBackStack(null)
.commit();
以下就v4包下的FragmentManager进行源码分析。
1、FragmentManager#beginTransaction
该方法返回一个BackStackRecord对象
该对象内部有一个成员变量mOps:
ArrayList<Op> mOps = new ArrayList<>();
Op是一个封装了fragment操作以及转场动画的bean:
static final class Op {
int cmd;//dvfragment的操作,如add remove replace等
Fragment fragment;
int enterAnim;
int exitAnim;
int popEnterAnim;
int popExitAnim;
}
2、BackStackRecord#add(id, fragment, tag)
该方法会将add操作封装成一个Op对象,然后存入mOps集合中。
3、 BackStackRecord#addToBackStack(null)
@Override
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;
}
注意mAddToBackStack 这个变量,很关键!该方法最重要的是让这个变量设为true。它的作用下面会讲到。
4、BackStackRecord#commit()
该方法最终调用commitInternal:
int commitInternal(boolean allowStateLoss) {
if (mCommitted) throw new IllegalStateException("commit already called");
mCommitted = true;
if (addToBackStack) {
//关键1
mIndex = mManager.allocBackStackIndex(this);
} else {
mIndex = -1;
}
//关键2
mManager.enqueueAction(this, allowStateLoss);
return mIndex;
}
如果调用了步骤3的addToBackStack方法,addToBackStack此时为true,进入判断执行关键1处代码,它的源码为:
ArrayList<BackStackRecord> mBackStackIndices;
ArrayList<Integer> mAvailBackStackIndices;
public int allocBackStackIndex(BackStackRecord bse) {
synchronized (this) {
if (mAvailBackStackIndices == null || mAvailBackStackIndices.size() <= 0) {
if (mBackStackIndices == null) {
mBackStackIndices = new ArrayList<BackStackRecord>();
}
int index = mBackStackIndices.size();
mBackStackIndices.add(bse);
return index;
} else {
//移除最后一个元素,返回最后一个元素的值。
int index = mAvailBackStackIndices.remove(mAvailBackStackIndices.size()-1);
mBackStackIndices.set(index, bse);
return index;
}
}
}
刚开始这段代码看的我是云里雾里,没办法,只能写个demo来debug运行不断分析了:
demo中不停的开启新fragment,且加入回退栈,此时mAvailBackStackIndices=null,走第一个判断,所有事务(BackStackRecord)都会添加到mBackStackIndices
集合中,并不会进else判断。
然后多次按返回键回退几个fragment,紧接着重新开启fragment,此时才会进入else判断,意味着mAvailBackStackIndices
这个集合此时不再为空且有内容了,更巧的是它的集合长度等于mAvailBackStackIndices
的长度,那么mAvailBackStackIndices
在哪里初始化并存放内容的呢?搜索mAvailBackStackIndices = new
,找到下面这段代码,并debug验证了每次按返回键移除fragment都会执行这段代码:
public void freeBackStackIndex(int index) {
synchronized (this) {
mBackStackIndices.set(index, null);
if (mAvailBackStackIndices == null) {
//在这里初始化了
mAvailBackStackIndices = new ArrayList<Integer>();
}
if (DEBUG) Log.v(TAG, "Freeing back stack index " + index);
//最后添加到mAvailBackStackIndices 后返回的index,会陆续添加到mAvailBackStackIndices中。
mAvailBackStackIndices.add(index);
}
}
总结下mBackStackIndices
和mAvailBackStackIndices
的操作:
前者会将BackStackRecord对象存入,这很正常;后者作用是:在从mBackStackIndices
集合中移除BackStackRecord对象的时候,将该被移除的BackStackRecord对象所在原集合中的index存入mAvailBackStackIndices
,注意加粗的移除,方式并非直接remove,而是ArrayList.set(index,null)。
为什么不直接用mBackStackIndices
,添加就add,移除就remove呢?
我猜想可能是mBackStackIndices是ArrayList,ArryList基于数组实现,这样避免了释放数组空间并再次开辟的耗时,达到空间换时间提高效率的目的。
至于mBackStackIndices
有啥用?好像跟什么adb命令,打印输出Activity信息啥的有关......走错码头了,看关键2吧。
5、FragmentManager#enqueueAction(OpGenerator action, boolean allowStateLoss)
关键2处代码调用mManager.enqueueAction(this, allowStateLoss),参数this即BackStackRecord对象。
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<>();
}
//将action添加到mPendingActions集合中
mPendingActions.add(action);
//执行action任务
scheduleCommit();
}
}
scheduleCommit()方法很简单,它利用handler,将任务发送到主线程的任务队列,执行execPendingActions():
public boolean execPendingActions() {
ensureExecReady(true);
boolean didSomething = false;
while (generateOpsForPendingActions(mTmpRecords, mTmpIsPop)) {
mExecutingActions = true;
try {
removeRedundantOperationsAndExecute(mTmpRecords, mTmpIsPop);
} finally {
cleanupExec();
}
didSomething = true;
}
doPendingDeferredStart();
burpActive();
return didSomething;
}
while循环的判断条件执行generateOpsForPendingActions:
private boolean generateOpsForPendingActions(ArrayList<BackStackRecord> records,
ArrayList<Boolean> isPop) {
boolean didSomething = false;
synchronized (this) {
//当集合为空或没内容时,返回false,防止while循环无限轮询
if (mPendingActions == null || mPendingActions.size() == 0) {
return false;
}
final int numActions = mPendingActions.size();
for (int i = 0; i < numActions; i++) {
//这里是关键,且generateOps返回值关系到上面的while循环
didSomething |= mPendingActions.get(i).generateOps(records, isPop);
}
//清空集合
mPendingActions.clear();
mHost.getHandler().removeCallbacks(mExecCommit);
}
return didSomething;
}
generateOps方法点进入,发现是OpGenerator接口的一个抽象方法,它的实现其中一个是在BackStackRecord中,那就看一下,
BackStackRecord#generateOps:
@Override
public boolean generateOps(ArrayList<BackStackRecord> records, ArrayList<Boolean> isRecordPop) {
records.add(this);
isRecordPop.add(false);
if (mAddToBackStack) {
//关键
mManager.addBackStackState(this);
}
//始终返回true,上面的while条件一定成立
return true;
}
步骤3中,mAddToBackStack被设为true,进入判断,执行 mManager.addBackStackState(this);回到FragmentManager中来:
void addBackStackState(BackStackRecord state) {
if (mBackStack == null) {
mBackStack = new ArrayList<BackStackRecord>();
}
mBackStack.add(state);
}
至此,我们可以说,凡是调用了.addToBackStack(null)
方法,都会将相关的BackStackRecord放入FragmentManager中的成员变量mBackStack集合中。
generateOps方法这里始终返回true,那么就会执行while内的任务removeRedundantOperationsAndExecute(mTmpRecords, mTmpIsPop);
,看名字是移除多余的操作并执行,然后经过一系列调用,最终执行的是record.executePopOps(moveToState);
或者是record.executeOps()
方法。先看record.executeOps():
6、BackStackRecord#executeOps
void executeOps() {
final int numOps = mOps.size();
for (int opNum = 0; opNum < numOps; opNum++) {
final Op op = mOps.get(opNum);
final Fragment f = op.fragment;
if (f != null) {
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;
case OP_SET_PRIMARY_NAV:
mManager.setPrimaryNavigationFragment(f);
break;
case OP_UNSET_PRIMARY_NAV:
mManager.setPrimaryNavigationFragment(null);
break;
default:
throw new IllegalArgumentException("Unknown cmd: " + op.cmd);
}
if (!mReorderingAllowed && op.cmd != OP_ADD && f != null) {
mManager.moveFragmentToExpectedState(f);
}
}
if (!mReorderingAllowed) {
// Added fragments are added at the end to comply with prior behavior.
mManager.moveToState(mManager.mCurState, true);
}
}
遍历BackStackRecord对象中的mOps 集合,swith到mOps对象封装的任务,最终调用FragmentManager的相关方法执行该任务。
网友评论