从源码角度解释 fragment 在remove之后又调用 onCreateView

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zxd_Android/article/details/82285702

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。

扫描二维码关注公众号,回复: 3033393 查看本文章

猜你喜欢

转载自blog.csdn.net/zxd_Android/article/details/82285702