fragment 自从被Android官方推出以来,就得到了广泛的应用,很多项目中都会使用多个fragment代替Activity进行页面展示,但是由于fragment使用起来相对复杂,如果不是很熟悉,使用起来就会存在一些问题,很难定位,下面我就举出一些我之前项目中存在的部分问题,并且从源码角度进行分析。
1、按返回键,明明fragment应该被销毁,为什么fragment又出来呢,onCreateView生命周期又走了一次?
我先上一段日志:
CallFunctionFragment onCreateView 531831588 又被调用一次
导致界面又显现了一次
进入拨打
D/HomeFragment: ------------current state----------CALLING
D/CallFunctionFragment: onCreate 531831588
D/CallFunctionFragment: onDestroyView 109974074
D/CallFunctionFragment: onCreateView 531831588
D/CallFragment: onDestroyView 399275080
D/CallFragment: onDestroy 399275080
挂断
D/HomeFragment: ------------current state----------IDLE
D/baseFragment: showStartFragment
D/HomeFragment: onCreate 216469862
D/CallFunctionFragment: onDestroyView 531831588
D/HomeFragment: onDestroyView 407342206
D/HomeFragment: onCreateView 216469862
D/HomeFragment: ------------current state----------TS_NONE
进入拨号页面
D/CallFunctionFragment: onCreate 281308227
D/CallFunctionFragment: onCreateView 281308227
D/CallFragment: onCreate 99798009
D/CallFragment: onCreateView 99798009
按返回键
D/CallFunctionFragment: onDestroyView 281308227
//该 fragment 在上面已经onDestroyView掉了,现在按理不应该再出来,但是现在又显现了
08-31 17:17:20.839 31056-31056 D/CallFunctionFragment: onCreateView 531831588
D/CallFragment: onCreate 344665781
D/CallFragment: onDestroyView 99798009
D/CallFragment: onCreateView 344665781
D/CallFunctionFragment: onDestroy 281308227
按返回键,系统调用的是popBackStackImmediate()方法,会从FragmentTransaction栈取出最近的一个事物操作,FragmentTransaction 在底层对应的BackStackRecord类,popBackStackImmediate最终调用到
popFromBackStack()方法。
按 返回键
public void onBackPressed() {
if (mActionBar != null && mActionBar.collapseActionView()) {
return;
}
//调用这里
if (!mFragments.getFragmentManager().popBackStackImmediate()) {
finishAfterTransition();
}
}
调到fragmentManager popBackStackImmediate
@Override
public boolean popBackStackImmediate() {
checkStateLoss();
executePendingTransactions();
return popBackStackState(mHost.getHandler(), null, -1, 0);
}
boolean popBackStackState(Handler handler, String name, int id, int flags) {
if (mBackStack == null) {
return false;
}
if (name == null && id < 0 && (flags&POP_BACK_STACK_INCLUSIVE) == 0) {
int last = mBackStack.size()-1;
if (last < 0) {
return false;
}
//此处重点,取出最顶部的事物
final BackStackRecord bss = mBackStack.remove(last);
SparseArray<Fragment> firstOutFragments = new SparseArray<Fragment>();
SparseArray<Fragment> lastInFragments = new SparseArray<Fragment>();
if (mCurState >= Fragment.CREATED) {
bss.calculateBackFragments(firstOutFragments, lastInFragments);
}
bss.popFromBackStack(true, null, firstOutFragments, lastInFragments);
reportBackStackChanged();
}
我们看下 popFromBackStack方法
public TransitionState popFromBackStack(boolean doStateMove, TransitionState state,
SparseArray<Fragment> firstOutFragments, SparseArray<Fragment> lastInFragments) {
if (FragmentManagerImpl.DEBUG) {
Log.v(TAG, "popFromBackStack: " + this);
LogWriter logw = new LogWriter(Log.VERBOSE, TAG);
PrintWriter pw = new FastPrintWriter(logw, false, 1024);
dump(" ", null, pw, null);
pw.flush();
}
if (mManager.mCurState >= Fragment.CREATED) {
if (state == null) {
if (firstOutFragments.size() != 0 || lastInFragments.size() != 0) {
state = beginTransition(firstOutFragments, lastInFragments, true);
}
} else if (!doStateMove) {
setNameOverrides(state, mSharedElementTargetNames, mSharedElementSourceNames);
}
}
bumpBackStackNesting(-1);
//从链表尾部开始遍历
//下面对应的逆反操作
Op op = mTail;
while (op != null) {
switch (op.cmd) {
case OP_ADD: {
Fragment f = op.fragment;
f.mNextAnim = op.popExitAnim;
mManager.removeFragment(f,
FragmentManagerImpl.reverseTransit(mTransition),
mTransitionStyle);
}
break;
case OP_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.popExitAnim;
mManager.detachFragment(f,
FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle);
}
break;
default: {
throw new IllegalArgumentException("Unknown cmd: " + op.cmd);
}
}
op = op.prev;
}
if (doStateMove) {
mManager.moveToState(mManager.mCurState,
FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle, true);
state = null;
}
if (mIndex >= 0) {
mManager.freeBackStackIndex(mIndex);
mIndex = -1;
}
return state;
}
这一段代码不难看出,从链表的尾部开始遍历,针对每一次操作都是逆反操作。
1、add 对应 remove
—解释了为什么栈顶的fragment,会被remove掉,走到onDestroyView
2、show 对应 hide
3、hide 对应 show
–解释了栈顶部第二个fragment会什么之前隐藏掉,顶部那个弹出去,自己又show出来了。
4、remove 对应 add .
–解释了我文章里面的日志,为什么明明我已经remove过得,又走了onCreateView方法。
下面是日志对应的代码
FragmentTracsaction在连续操作时候要特别小心,你看上图,连续三次操作,那么调用返回键,底层就会先remove最近的一个,可能add 前一个,再show上上一个fragment。