fragment操作流程
我们来看一下Fragment初始化的具体流程。拿add()举例:
FragmentManager:
@Override
public FragmentTransaction beginTransaction() {
return new BackStackRecord(this);
}
首先取得FragmentTranscation类型的BackStackRecord对象。
BackStackRecord:
在FragmentTranscaction调用add()之后会生成一个新的Op类来保存用户的操作。
private void doAddOp(int containerViewId, Fragment fragment, String tag, int opcmd) {
fragment.mFragmentManager = mManager;
...
Op op = new Op();
op.cmd = opcmd;
op.fragment = fragment;
addOp(op);
}
void addOp(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++;
}
之后会用BackStackRecord中的两个Op类(mHead,mTail)以链表的形式来保存用户的操作。
mHead,会在加入的时候遍历。
mTail,会在back退出的时候遍历。
最后来看看commit()是怎么实现的
首先如果设置为saveStack,那么会把当前的BackStackRecord对象add到FragmentManager的mBackStackIndices(Arraylist)中,并返回list.size(),来作为Id.
int commitInternal(boolean allowStateLoss) {
...
if (mAddToBackStack) {
mIndex = mManager.allocBackStackIndex(this);
} else {
mIndex = -1;
}
mManager.enqueueAction(this, allowStateLoss);
return mIndex;
}
FragmentManager会把这个BackStack对象加入到的Handle队列中执行。mPendingActions中保存了待处理的Runnable。可以用executePendingTransactions()来立刻遍历执行mPendingActions中的run.
mPendingActions.add(action);
if (mPendingActions.size() == 1) {
mActivity.mHandler.removeCallbacks(mExecCommit);
mActivity.mHandler.post(mExecCommit);
}
在run中,会根据用户操作状态(cmd)遍历mHead链表来执行对应FragmentManager中的方法,这里比较特殊的是replace();最后把BackStack对象存入Manager中的mBackStack集合中
public void run() {
if (FragmentManagerImpl.DEBUG) Log.v(TAG, "Run: " + this);
if (mAddToBackStack) {
if (mIndex < 0) {
throw new IllegalStateException("addToBackStack() called after commit()");
}
}
bumpBackStackNesting(1);
Op op = mHead;
while (op != null) {
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) {
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 = new ArrayList<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;
...
default: {
throw new IllegalArgumentException("Unknown cmd: " + op.cmd);
}
}
op = op.next;
}
mManager.moveToState(mManager.mCurState, mTransition,
mTransitionStyle, true);
if (mAddToBackStack) {
mManager.addBackStackState(this);
}
}
这里的 mAdded是Manager中的一个List,用来保存add进来的fragment对象。这里做了一个简单的比较,如果新的fragment与List中的fragment是同一个对象,那么直接跳过,什么都不做。
如果不是同一个对象,那就把List中的fragment删掉。按照这样的写法,最后一个GruopView中,只会剩下最新替换的Fragment。
可我通过实验发现,如果把多个fragment加入到同一个GruopVIew中,然后做replace(),那么会出现只替换了最后一个fragment,第一个消失,而且他保留的情况。这里我还要再看看,果如有明白的朋友可以告诉我是怎么回事。
FragmentManager:
把新的Fragment添加到总集合(ArrayList<Fragment> mAdded) 和活跃集合(ArrayList<Fragment> mActive)中,之后具体的操作都在moveToState中执行。
public void addFragment(Fragment fragment, boolean moveToStateNow) {
if (mAdded == null) {
mAdded = new ArrayList<Fragment>();
}
...
makeActive(fragment);
if (!fragment.mDetached) {
...
mAdded.add(fragment);
if (moveToStateNow) {
moveToState(fragment);
}
}
}
moveToState学习,请看学习3