Fragment-Transaction 源码分析
概述
这篇文章的简要分析了Activity中的Transaction和add,replace等操作以及backstack的工作原理。
分析transaction源码的原因是因为我在写一个测试代码的时候,发现replace并没有将之前所有添加到某个container id上的Fragment全部移除掉,觉得很奇怪。
查看官方API对replace的解释
Replace an existing fragment that was addedto a container. This is essentially the same as calling remove(Fragment) forall currently added fragments that were added with the same containerViewId andthen add(int,Fragment, String) with the same arguments given here.
怎么会和我测试的结果不一样,于是开始查看源代码。最后发现应该是一个Bug,然后将这个bug report在https://code.google.com/p/android/issues/detail?id=68856&colspec=ID%20Type%20Status%20Owner%20Summary%20Stars
看看是我理解得不透彻还是确实算个Bug,哈哈。
要测试的内容如下
首先我们以下面这段代码为例,来分析Fragment的add操作
点击一个Button的时候执行下面的操作
FragmentTransaction ft =getFragmentManager().beginTransaction();
ft.add(R.id.container,FragmentA.newInstance("1"));
ft.add(R.id.container,FragmentA.newInstance("2"));
ft.add(R.id.container,FragmentA.newInstance("3"));
ft.add(R.id.container,FragmentA.newInstance("4"));
ft.add(R.id.container,FragmentA.newInstance("5"));
ft.add(R.id.container,FragmentA.newInstance("6"));
ft.add(R.id.container,FragmentA.newInstance("7"));
ft.addToBackStack(null);
ft.commit();
接着点击另外一个按钮执行下面的操作:
FragmentTransaction ft =getFragmentManager().beginTransaction();
ft.replace(R.id.container,FragmentA.newInstance("replaced A"));
ft.addToBackStack(null);
ft.commit();
getFragmentManager
进入Activity的源码,我们发现Activity中有个FragmentManagerImpl,这个实例用来管理Fragment的添加,删除,以及保存当前的激活的Fragment,等。
Activity类
final FragmentManagerImpl mFragments = newFragmentManagerImpl();
public FragmentManager getFragmentManager() {
returnmFragments;
}
beginTransaction
当我们调用beginTransaction的时候,FragmentManager会为我们生成一个transaction,这个transaction其实是一个保存你即将进行的一些列操作的栈。比如你要add一个Fragment,接着又要replace一个Fragment,这两个操作都会被当做两个操作顺序的记录在这个transaction中。根据名字也可以看出来
(BackStackRecord,是一个实现了FragmentTransaction的类),
FragmentManagerImpl 类
ArrayList<BackStackRecord> mBackStackIndices;
@Override
public FragmentTransaction beginTransaction() {
return newBackStackRecord(this);
}
FragmentManager.add
接着我们调用了ft.add(R.id.cntainer, FragmentA.newInstance("1"));,这个操作将会向新生成的BackStackRecord对象中添加一个操作事件,即Op对象。Op对象相当于一个双向链表,记录了前一个操作和后一个操作。比如我们这次add了7个FragmentA,那么这7个操作会当成7个Op存放在这个新生成的BackStackRecord(就是一个Transaction)中。
public FragmentTransaction add(intcontainerViewId, Fragment fragment, String tag) {
doAddOp(containerViewId, fragment, tag, OP_ADD);
returnthis;
}
private void doAddOp(int containerViewId, Fragmentfragment, String tag, int opcmd) {
fragment.mFragmentManager = mManager;
if (tag!= null) {
if(fragment.mTag != null && !tag.equals(fragment.mTag)) {
throw new IllegalStateException("Can't change tag of fragment"
+ fragment + ":was " + fragment.mTag
+ " now " +tag);
}
fragment.mTag = tag;
}
if (containerViewId != 0) {
if(fragment.mFragmentId != 0 && fragment.mFragmentId != containerViewId){
throw new IllegalStateException("Can't change container ID offragment "
+ fragment + ":was " + fragment.mFragmentId
+ " now " +containerViewId);
}
fragment.mContainerId = fragment.mFragmentId = containerViewId;
}
//关键代码:生成Op来记录这次操作。
Op op =new Op();
op.cmd= opcmd;
op.fragment = fragment;
addOp(op);
}
//关键代码:将Op添加到新生成的这个BackStackRecord中,会将这次trascation事件中的每个Op顺序的记录下来。
voidaddOp(Op op) {
if(mHead == null) {
mHead = mTail = op;
} else{
op.prev = mTail;
mTail.next = op;
mTail = op;
}
op.enterAnim = mEnterAnim;
op.exitAnim = mExitAnim;
op.popEnterAnim = mPopEnterAnim;
op.popExitAnim= mPopExitAnim;
mNumOp++;
}
static finalclass Op {
Opnext;
Opprev;
intcmd;
Fragment fragment;
intenterAnim;
intexitAnim;
intpopEnterAnim;
intpopExitAnim;
ArrayList<Fragment> removed;
}
紧接着,我们调用了ft.addToBackStack(null);
publicFragmentTransaction addToBackStack(String name) {
if(!mAllowAddToBackStack) {
throw new IllegalStateException(
"This FragmentTransaction is not allowed to be added to the backstack.");
}
//关键代码:将mAddToBackStack设置成true,这会在commit的时候判断,以便于将这个transaction添加到FragmentManager的Back stack栈中
mAddToBackStack = true;
mName =name;
returnthis;
}
FragmentManager.commit
最后,我们调用了ft.commit(),然后,FragmentManager就会将这次的所有Op放到主线程中去按顺序执行。BackStackRecord实现了run方法,所以在主线程执行的时候会调用run方法中的代码。
public int commit() {
returncommitInternal(false);
}
intcommitInternal(boolean allowStateLoss) {
if(mCommitted) throw new IllegalStateException("commit alreadycalled");
if(FragmentManagerImpl.DEBUG) {
Log.v(TAG, "Commit: " + this);
LogWriter logw = new LogWriter(TAG);
PrintWriter pw = new PrintWriter(logw);
dump(" ", null, pw,null);
}
mCommitted = true;
//关键代码:判断是否需要添加到Back stack
if(mAddToBackStack) {
mIndex = mManager.allocBackStackIndex(this);
} else{
mIndex = -1;
}
//关键代码:将这个transaction放入到FragmentManager的执行队列中去,当要开始执行这个transaction的时候,就会调用到BackStackRecord的run方法。
mManager.enqueueAction(this, allowStateLoss);
returnmIndex;
}
这里,我们看看FragmentManager的allocBackStackIndex方法。我们发现FragmentManger的back stack就是一个ArrayList,里面记录了一些列的transaction。
publicint allocBackStackIndex(BackStackRecord bse) {
synchronized (this) {
if (mAvailBackStackIndices == null|| mAvailBackStackIndices.size() <= 0) {
if (mBackStackIndices == null){
//关键代码:生成Back stack的list
mBackStackIndices = newArrayList<BackStackRecord>();
}
int index =mBackStackIndices.size();
if (DEBUG) Log.v(TAG,"Setting back stack index " + index + " to " + bse);
//关键代码:添加这次的transaction到Backstack的list
mBackStackIndices.add(bse);
return index;
} else {
int index =mAvailBackStackIndices.remove(mAvailBackStackIndices.size()-1);
if (DEBUG) Log.v(TAG,"Adding back stack index " + index + " with " + bse);
mBackStackIndices.set(index, bse);
return index;
}
}
}
Add,replace源码
继续刚才的情况,在commit之后,会把这次的transaction放到FragmentManager的执行队列中去,当开始执行这个Transaction的时候,会调用到这个BackStackRecord的run方法。这个方法中会顺序的调用这个BackStackRecord中的所有Op,我们刚才已经分析指导,每个add,remove等操作都当做Op存放在这个Transaction中,BackStackRecord就是一个Transaction的实例。在处理一个Op的时候,会根据这个Op的cmd属性来进行add,remove,replace等操作。
publicvoid run() {
if (FragmentManagerImpl.DEBUG)Log.v(TAG, "Run: " + this);
if (mAddToBackStack) {
if (mIndex < 0) {
throw newIllegalStateException("addToBackStack() called after commit()");
}
}
bumpBackStackNesting(1);
Op op = mHead;
//关键代码:顺序处理这个transaction中的所有op
while (op != null) {
//关键代码:根据op的cmd属性分别进行add,replace等操作
switch (op.cmd) {
case OP_ADD: {
Fragment f = op.fragment;
f.mNextAnim = op.enterAnim;
mManager.addFragment(f,false);
} break;
case OP_REPLACE: {
Fragment f = op.fragment;
if(mManager.mAdded != null) {
//关键代码:我们这篇文章的重点来了,为什么只移除掉了一部分的Fragment呢?在这个For循环中,本来目的是要找出所有添加到这个mContainerId上的所有的Fragment,将他们从FragmentManager管理的mAdded表(这个表记录了Add到这个Activity的Fragment)中移除。但是我们看到在for循环里,i在不断的增加,但是实际上当从mManager .mAdded移除掉一个Fragment的时候,这个i的位置已经不对了。比如最开始我们的mAdded里面有序号为1,2,3,4,5,6,7的Fragment,在i
==0的时候,移除掉了序号为1的Fragment,所以mAdded里面还有序号为2,3,4,5,6,7的Fragment。接着i==1的时候,移除序号为3的Fragment。依次类推,序号为2,4,6的Fragment就没有被移除掉,所以就出现了文章开头处的问题。
for (int i=0;i<mManager.mAdded.size(); i++) {
Fragment old =mManager.mAdded.get(i);
if(FragmentManagerImpl.DEBUG) Log.v(TAG,
"OP_REPLACE: adding=" + f + " old=" + old);
if (f == null ||old.mContainerId == f.mContainerId) {
if (old == f) {
op.fragment= f = null;
} else {
if(op.removed == null) {
op.removed = newArrayList<Fragment>();
}
op.removed.add(old);
old.mNextAnim = op.exitAnim;
if(mAddToBackStack) {
old.mBackStackNesting += 1;
if(FragmentManagerImpl.DEBUG) Log.v(TAG, "Bump nesting of "
+ old + " to " + old.mBackStackNesting);
}
mManager.removeFragment(old, mTransition, mTransitionStyle);
}
}
}
}
if (f != null) {
f.mNextAnim =op.enterAnim;
mManager.addFragment(f,false);
}
} break;
case OP_REMOVE: {
Fragment f = op.fragment;
f.mNextAnim = op.exitAnim;
mManager.removeFragment(f,mTransition, mTransitionStyle);
} break;
case OP_HIDE: {
Fragment f = op.fragment;
f.mNextAnim = op.exitAnim;
mManager.hideFragment(f,mTransition, mTransitionStyle);
} break;
case OP_SHOW: {
Fragment f = op.fragment;
f.mNextAnim = op.enterAnim;
mManager.showFragment(f,mTransition, mTransitionStyle);
} break;
case OP_DETACH: {
Fragment f = op.fragment;
f.mNextAnim = op.exitAnim;
mManager.detachFragment(f, mTransition,mTransitionStyle);
} break;
case OP_ATTACH: {
Fragment f = op.fragment;
f.mNextAnim = op.enterAnim;
mManager.attachFragment(f,mTransition, mTransitionStyle);
} break;
default: {
throw newIllegalArgumentException("Unknown cmd: " + op.cmd);
}
}
op = op.next;
}
mManager.moveToState(mManager.mCurState,mTransition,
mTransitionStyle, true);
//关键代码:将这个Transaction添加到backstack中去。
if (mAddToBackStack) {
mManager.addBackStackState(this);
}
}
按back回退
按back首先调用的是Activity的onBackPressed
public void onBackPressed() {
//关键代码:让Activity的backstack处理,如果返回false,表示没有需要back的,所以当前activity就finish掉。
if(!mFragments.popBackStackImmediate()) {
finish();
}
}
接着会去到FragmentManager的popBackStackImmediate
public boolean popBackStackImmediate() {
checkStateLoss();
executePendingTransactions();
returnpopBackStackState(mActivity.mHandler, null, -1, 0);
}
booleanpopBackStackState(Handler handler, String name, int id, int flags) {
if(mBackStack == null) {
return false;
}
if(name == null && id < 0 && (flags&POP_BACK_STACK_INCLUSIVE)== 0) {
intlast = mBackStack.size()-1;
if(last < 0) {
return false;
}
finalBackStackRecord bss = mBackStack.remove(last);
//关键代码:从FragmentManager管理的backstack中取出一个transaction(就是我们刚才说的BackStackRecord),调用他的popFromBackStack来还原之前的状态。
bss.popFromBackStack(true);
reportBackStackChanged();
} else{
intindex = -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;
}
final ArrayList<BackStackRecord> states
= new ArrayList<BackStackRecord>();
for(int i=mBackStack.size()-1; i>index; i--) {
states.add(mBackStack.remove(i));
}
final int LAST = states.size()-1;
for(int i=0; i<=LAST; i++) {
if (DEBUG) Log.v(TAG, "Popping back stack state: " +states.get(i));
states.get(i).popFromBackStack(i == LAST);
}
reportBackStackChanged();
}
returntrue;
}
紧接着我们看看BackStackRecord是怎么来处理的
publicvoid popFromBackStack(boolean doStateMove) {
if (FragmentManagerImpl.DEBUG) {
Log.v(TAG, "popFromBackStack:" + this);
LogWriter logw = new LogWriter(TAG);
PrintWriter pw = newPrintWriter(logw);
dump(" ", null, pw, null);
}
bumpBackStackNesting(-1);
//关键代码:在这里又开始循环取出这个transaction中的Op(就是那些add,replace等操作)。然后做出一些跟刚才add,replace相反的操作.
Op op = mTail;
while (op != null) {
switch (op.cmd) {
//关键代码:如果之前这个Transaction是Add操作,那么我们就用FragmentManager来将这个Fragment移除掉。
case OP_ADD: {
Fragment f = op.fragment;
f.mNextAnim =op.popExitAnim;
mManager.removeFragment(f,
FragmentManagerImpl.reverseTransit(mTransition),
mTransitionStyle);
} break;
//关键代码:如果之前是Replace操作,我们就将之前在Replace操作的时候remove掉得那些Fragment再次add进来
caseOP_REPLACE: {
Fragment f = op.fragment;
if (f != null) {
f.mNextAnim =op.popExitAnim;
mManager.removeFragment(f,
FragmentManagerImpl.reverseTransit(mTransition),
mTransitionStyle);
}
if (op.removed != null) {
for (int i=0;i<op.removed.size(); i++) {
Fragment old = op.removed.get(i);
old.mNextAnim =op.popEnterAnim;
mManager.addFragment(old, false);
}
}
} break;
case OP_REMOVE: {
Fragment f = op.fragment;
f.mNextAnim =op.popEnterAnim;
mManager.addFragment(f,false);
} break;
case OP_HIDE: {
Fragment f = op.fragment;
f.mNextAnim =op.popEnterAnim;
mManager.showFragment(f,
FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle);
} break;
case OP_SHOW: {
Fragment f = op.fragment;
f.mNextAnim =op.popExitAnim;
mManager.hideFragment(f,
FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle);
} break;
case OP_DETACH: {
Fragment f = op.fragment;
f.mNextAnim =op.popEnterAnim;
mManager.attachFragment(f,
FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle);
} break;
case OP_ATTACH: {
Fragment f = op.fragment;
f.mNextAnim =op.popEnterAnim;
mManager.detachFragment(f,
FragmentManagerImpl.reverseTransit(mTransition),mTransitionStyle);
} break;
default: {
throw newIllegalArgumentException("Unknown cmd: " + op.cmd);
}
}
op = op.prev;
}
if (doStateMove) {
mManager.moveToState(mManager.mCurState,
FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle,true);
}
if (mIndex >= 0) {
mManager.freeBackStackIndex(mIndex);
mIndex = -1;
}
}