您的位置:首页 > 其它

Fragment的添加和删除及其源码分析

2016-06-01 19:40 471 查看
Android API中FragmentManager和FragmentTransaction这两个类中提供了大量的对Fragment进行操作的方法,这里做记录和整理。

查找Fragment

其中FragmentManager中维护了一个队列,用于存放Fragment实例,我们添加的Fragment可以通过以下方法查找

Fragment的查找

getFragmentManager()

findFragmentById():根据布局xml文件中声明的id查找对应的Fragment;

findFragmentByTag():根据动态添加Fragment的TAG值,查找对应的Fragment;

getFragmentManager().findFragmentById(R.id.fragment_list);
getFragmentManager().findFragmentById(TAG);


查找嵌套在Fragment内部的Fragment

getChildFragmentManager():当Fragment中嵌套着另外一个Fragment,注意这时候要使用getChildFragmentManager()获取对应的FragmentManager,否则会查找不到该Fragment导致空指针异常

TestListFragment testListFragment = (TestListFragment) getChildFragmentManager().findFragmentById(R.id.fragment_list);


Fragment的添加,删除

添加Fragment

add():向Activity中添加Fragment;

remove():删除Fragment,当该Fragment没有入栈,那么该Fragment的实例将会被删除,反之,该实例不会被删除;

replace():其实是先remove()然后调用add();

源码分析

add()方法解析

add()方法是FragmentTransaction中的方法,我们从这个类开始,进入FragmentTransaction后,发现该类是一个抽象类。查找该类的实现类:BackStackRecord,该类还实现了Runnable接口,我们来看看该类中的add()方法

public FragmentTransaction add(Fragment fragment, String tag) {
doAddOp(0, fragment, tag, OP_ADD);
return this;
}

public FragmentTransaction add(int containerViewId, Fragment fragment) {
doAddOp(containerViewId, fragment, null, OP_ADD);
return this;
}

public FragmentTransaction add(int containerViewId, Fragment fragment, String tag) {
doAddOp(containerViewId, fragment, tag, OP_ADD);
return this;
}


发现add()的三个重载方法都调用doAppOp()这个方法,另外有一个地方我们需要注意,该方法的最后都加了一个标记参数:OP_ADD,我们来看看这个方法

private void doAddOp(int containerViewId, Fragment fragment, 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 of fragment "
+ fragment + ": was " + fragment.mFragmentId
+ " now " + containerViewId);
}
fragment.mContainerId = fragment.mFragmentId = containerViewId;
}

Op op = new Op();
op.cmd = opcmd;
op.fragment = fragment;
addOp(op);


我们可以看到该方法将参数进行了传递,最后调用了addOp()这个方法,上代码:

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++;
}


该方法中,只是进行了op对象的传递,和动画的参数传递,然后就没有下文了,难道到这就断了?并不是,在添加Fragment的时候,最后都会调用commit()方法,添加的Fragment才会真正的被添加上去,那我们来看看commit()方法的源码

public int commit() {
return commitInternal(false);
}


其内部调用的是commitInternal(),继续看源码

int commitInternal(boolean allowStateLoss) {
if (mCommitted) throw new IllegalStateException("commit already called");
if (FragmentManagerImpl.DEBUG) Log.v(TAG, "Commit: " + this);
mCommitted = true;
if (mAddToBackStack) {
mIndex = mManager.allocBackStackIndex(this);
} else {
mIndex = -1;
}
mManager.enqueueAction(this, allowStateLoss);
return mIndex;
}


该方法的最后,将该类加入了一个Action队列
mManager.enqueueAction(this, allowStateLoss);
,继续看

public void enqueueAction(Runnable action, boolean allowStateLoss) {
if (!allowStateLoss) {
checkStateLoss();
}
synchronized (this) {
if (mActivity == null) {
throw new IllegalStateException("Activity has been destroyed");
}
if (mPendingActions == null) {
mPendingActions = new ArrayList<Runnable>();
}
mPendingActions.add(action);
if (mPendingActions.size() == 1) {
mActivity.mHandler.removeCallbacks(mExecCommit);
mActivity.mHandler.post(mExecCommit);
}
}
}


该方法中将BackStackRecord加入了mPendingActions集合,接着来看这句代码
mActivity.mHandler.post(mExecCommit);
,Handler执行mExecCommit,我们再来看看mExecCommit是什么

Runnable mExecCommit = new Runnable() {
@Override
public void run() {
execPendingActions();
}
};


其也是一个Runnable,run方法中执行了execPendingActions(),我们再来看看这个方法:

/**
* Only call from main thread!
*/
public boolean execPendingActions() {
if (mExecutingActions) {
throw new IllegalStateException("Recursive entry to executePendingTransactions");
}

if (Looper.myLooper() != mActivity.mHandler.getLooper()) {
throw new IllegalStateException("Must be called from main thread of process");
}

boolean didSomething = false;

while (true) {
int numActions;

synchronized (this) {
if (mPendingActions == null || mPendingActions.size() == 0) {
return didSomething;
}

numActions = mPendingActions.size();
if (mTmpActions == null || mTmpActions.length < numActions) {
mTmpActions = new Runnable[numActions];
}
mPendingActions.toArray(mTmpActions);
mPendingActions.clear();
mActivity.mHandler.removeCallbacks(mExecCommit);
}

mExecutingActions = true;
for (int i=0; i<numActions; i++) {
mTmpActions[i].run();
mTmpActions[i] = null;
}
mExecutingActions = false;
didSomething = true;
}
}


该方法中mPendingActions与数组mTmpActions完成了置换,(不明白的可以去看下,toArray()方法的内部实现)最后for循环依次执行run方法。终于回归正轨,这里看下BackStackRecord中的run方法

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 (old.mContainerId == f.mContainerId) {
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);
}
}
}
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 new IllegalArgumentException("Unknown cmd: " + op.cmd);
}
}

op = op.next;
}

mManager.moveToState(mManager.mCurState, mTransition,
mTransitionStyle, true);

if (mAddToBackStack) {
mManager.addBackStackState(this);
}
}


内容比较庞大,但是还是决定贴出来,这里要说一下我们在之前提到的OP_ADD,这就是添加的标记,它的作用在该方法中提现出来了,除此以外,还有别的状态标记:replace,remove,hide,show,detach,attach这些;最后这些对应的标记下都调用了FragmentManagerImp中对应的方法。这里就不再贴源码了,感兴趣的朋友可以自行查看。

该方法最后两段代码稍微提一下:

mManager.moveToState(mManager.mCurState, mTransition,
mTransitionStyle, true);


这段代码中的moveToState方法体现了Fragment在不同生命周期状态下所进行的一些操作,大家可以看看源码

if (mAddToBackStack) {
mManager.addBackStackState(this);
}


这段代码用来设置回退栈

remove()方法解析

结论上面已经贴出,这里只贴下证明结论的源码和简单解析

public void removeFragment(Fragment fragment, int transition, int transitionStyle) {
if (DEBUG) Log.v(TAG, "remove: " + fragment + " nesting=" + fragment.mBackStackNesting);
final boolean inactive = !fragment.isInBackStack();
if (!fragment.mDetached || inactive) {
mAdded.remove(fragment);
if (fragment.mHasMenu && fragment.mMenuVisible) {
mNeedMenuInvalidate = true;
}
fragment.mAdded = false;
fragment.mRemoving = true;
moveToState(fragment, inactive ? Fragment.INITIALIZING : Fragment.CREATED,
transition, transitionStyle);
}
}


这句代码
final boolean inactive = !fragment.isInBackStack();
,获取当前fragment是否加入回退栈的状态,如果没加入将会进入方法体执行
mAdded.remove(fragment);
,删除fragment实例

replace()方法解析

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 (old.mContainerId == f.mContainerId) {
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);
}
}
}
f.mNextAnim = op.enterAnim;
mManager.addFragment(f, false);
} break;


上面源码直接可以看出,replace方法先调用了
mManager.removeFragment(old, mTransition, mTransitionStyle);
,最后调用了
mManager.addFragment(f, false);
,这也验证了我们之前的结论。

这也是add方法与replace方法的区别
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息