你真的了解Fragment么?

295 阅读9分钟

概述: Fragment从commit到resume状态的过程是?

这一part,我们以activity通过 replace的方案启动一个fragment 做为case,梳理一下 起启动过程 fragment启动流程图.png fragment的启动过程本质上是view的加载过程,只不过给view增加了生命周期的能力, 可以将上述的流程图抽象为下面几个步骤

  1. new一个事务(图中的BackStackRecord)

  2. 往事务添加需要执行的 命令(图中replace)

  3. 提交该事务 (图中commitInternal)

  4. 将命令打散(expandOps)为一个个的子命令执行。比如 (replace -> remove + add)

  5. 命令执行过程中,会改变Fragment的状态,作为computeExpectedState函数的入参去计算最终态。

比如 add命令 -> addFragment -> fragment.mAdded = true, fragment.mRemoving = false 。 再computeExpectedState中计算可以得到 最终态是resume。比如 add命令 -> addFragment -> fragment.mAdded = true, fragment.mRemoving = false 。 再computeExpectedState中计算可以得到 最终态是resume。

  1. 通过moveToExpectedState执行fragment的生命周期, 直到达到最终态Resume.

从提交开始:fragment中各种 命令& commit xxx到底有撒区别

一段典型的fragment初始化代码,这一part

fragmentManager
// new一个事务
.beginTransaction()
// 往事务添加需要执行的 命令
    .replace(R.id.frag_entrance_main_container, Test1Fragment.newInstance("1", "2"), "test1")
    // 提交
    .commit()

两个问题

  1. fragment初始化两种命令可执行,add, replace。他们区别是啥?

  2. 提交多4种方法,他们区别是撒?

commit的四种方法 如果从activity里启动,两者基本无区别,因为此时replace命令只会解析成 add

如果从【old fragment】里启动兄弟节点【new fragment】,replace会解析(expandOps)成 remove + add。

commitXXX

image

如上图,fragment有四种commit, 之所以有四种,是基于两个变量即allowStateLoss ,Now

allowStateLoss:表示宿主activity在后台能否改变 fragment的状态,true表示可以改变,false表示不能改变,如果改变了会抛异常

case: activity A在onStop过程中,执行了fragment相关命令,会抛出异常

Now: 表示执行fragment的生命周期是否需要post出去, true表示不用post,false表示需要post

表格如下:

allowStateLossNow含义使用场景
commitfalsefalse无场景
commitAllowingStateLosstruefalse多个事务整合在一起提交
CommitNowfalsetrue无场景
commitNowAllowingStateLosstruetrue只提交一个事务

一般情况下会调用commitAllowingStateLoss 或者 commitNowAllowingStateLoss。

状态计算:Fragment中的命令是如何驱动状态变化的

这里以 replace命令为例,

  1. 首先replace会解析成两个子命令 add + remove, 其中add是指:add(新增fragment),remove是指:remove(旧fragment)

  2. 这里我们看一下remove(旧fragment)流程

// BackStackRecord -> excuteOps
void executeOps() {
    case OP_ADD:
        f.setAnimations(op.mEnterAnim, op.mExitAnim, op.mPopEnterAnim, op.mPopExitAnim);
        mManager.setExitAnimationOrder(f, false);
        mManager.addFragment(f);
        break;    
    case OP_REMOVE:
        f.setAnimations(op.mEnterAnim, op.mExitAnim, op.mPopEnterAnim, op.mPopExitAnim);
        // 取改变fragment的状态
        mManager.removeFragment(f);
        break;
}
// FragmentManager -> removeFragment
void removeFragment(@NonNull Fragment fragment) {
    if (isLoggingEnabled(Log.VERBOSE)) {
        Log.v(TAG, "remove: " + fragment + " nesting=" + fragment.mBackStackNesting);
    }
    final boolean inactive = !fragment.isInBackStack();
    if (!fragment.mDetached || inactive) {
        mFragmentStore.removeFragment(fragment);
        if (isMenuAvailable(fragment)) {
            mNeedMenuInvalidate = true;
        }
        fragment.mRemoving = true;
        setVisibleRemovingFragment(fragment);
    }
}
// FragmentStore -> removeFragment
void removeFragment(@NonNull Fragment fragment) {
    synchronized (mAdded) {
        mAdded.remove(fragment);
    }
    fragment.mAdded = false;
}

int computeExpectedState() {
    // If the FragmentManager is null, disallow changing the state at all
    if (mFragment.mFragmentManager == null) {
        return mFragment.mState;
    }
     // added = false
    if (!mFragment.mAdded) {
        maxState = Math.min(maxState, Fragment.CREATED);
    }
    SpecialEffectsController.Operation.LifecycleImpact awaitingEffect = null;
    if (FragmentManager.USE_STATE_MANAGER && mFragment.mContainer != null) {
        SpecialEffectsController controller = SpecialEffectsController.getOrCreateController(
                mFragment.mContainer, mFragment.getParentFragmentManager());
        awaitingEffect = controller.getAwaitingCompletionLifecycleImpact(this);
    }
    if (awaitingEffect == SpecialEffectsController.Operation.LifecycleImpact.ADDING) {
        // Fragments awaiting their enter effects cannot proceed beyond that state
        maxState = Math.min(maxState, Fragment.AWAITING_ENTER_EFFECTS);
    } else if (awaitingEffect == SpecialEffectsController.Operation.LifecycleImpact.REMOVING) {
        // Fragments that are in the process of being removed shouldn't go below that state
        maxState = Math.max(maxState, Fragment.AWAITING_EXIT_EFFECTS);
    } else if (mFragment.mRemoving) {
        if (mFragment.isInBackStack()) {
            // 如果在堆栈里,就只执行 最终态就是CREATED
            maxState = Math.min(maxState, Fragment.CREATED);
        } else {
            maxState = Math.min(maxState, Fragment.INITIALIZING);
        }
    }
    return maxState;
}
  • computeExpectedState 计算出的状态是 Fragment.CREATED 或者Fragment.INITIALIZING

  • 当前状态是Resume

  • 所以通过moveToExpectState 去将状态扭转到 Fragment.CREATED 或者Fragment.INITIALIZING

状态迁移:fragment为何要区分这么多状态

从源码可以看到fragment状态如下

static final int INITIALIZING = -1;          // Not yet attached.
static final int ATTACHED = 0;               // Attached to the host.
static final int CREATED = 1;                // Created.
static final int VIEW_CREATED = 2;           // View Created.

static final int ACTIVITY_CREATED = 4;       // Fully created, not started.
static final int STARTED = 5;                // Created and started, not resumed.

static final int RESUMED = 7;                // Created started and resumed.

可以用分层的思想思考下,为什么要分这么多状态,每种状态做了什么。下图是状态 和 事件的关系:

计算当前状态S1, 需要扭转的状态S2。 如果是升级即S2 > S1则走 正向状态扭转,如果是降级,则走逆向状态扭转

状态管理

onAttach和onDetach是逆操作,同理 onCreate和onDestory也互为可逆。所以之前正向事件做了什么基本就知道了逆向事件做了什么了

  • onAttach: 宿主对象赋值
  • onCreate: 对齐activity,并在内部恢复一些属性
  • onViewCreate: 加载视图
  • onStart: 对齐activity
  • onResume: fragment进入运行态且对齐activity onresume

纵向管理:Fragment是如何管理子fragment的

通过FragmentManager管理

Fragment {
    // 访问父节点,父节点只有一个
    Fragment mParentFragment
    // 用于访问 兄弟fragment, 多个
    FragmentManager parentFragmentManager
    // 用于访问当前framgent的子fragment, 多个
    FragmentManager childFragmentManager
}

FragmentManager {
    // 可以理解为 List<Fragment>
    FragmentStore fragmentStore
}

数据结构 和如下gpt回答的类似

image

横向管理:Fragment如何管理兄弟节点的

纵向fragment通过树结构来管理,横向兄弟fragment之间关系 用堆栈来管理

横向管理

如上图:一个BackStackRecord表示一个事务,一个事务由多个命令构成,当回滚事务时(即调用popBackStack),做逆操作即可。上图可拆分成如下步骤

  1. push一个BackStackRecord(add) -> add fragmentA

  2. push 一个 BackStackRecord(Replace) -> remove fragmentA + add fragmentB

开始回滚

  1. fragmentB popBack -> add fragmentA + remove FragmentB

  2. fragmentA popBack -> remove FragmentA

popBackStack源码中,会执行executePopOps 如下 image.png

Fragment中是如何处理状态销毁和恢复的?

核心思路:销毁时存储元数据,恢复时,通过元数据 对framgment进行视图重建。然后通过业务数据绑定视图

存储的元数据结构为 FragmentState

final String mClassName;
final String mWho;
final boolean mFromLayout;
final int mFragmentId;
final int mContainerId;
final String mTag;
final boolean mRetainInstance;
final boolean mRemoving;
final boolean mDetached;
final Bundle mArguments;
final boolean mHidden;
final int mMaxLifecycleState;

下图是存储FragmentState流程

image.png 下图是fragment的恢复流程:

image.png

  • 屏幕发生了旋转,fragment会通过反射重新实例化。这个过程中会调用 fragment的无参构造函数。

  • makeActive 恢复FrammentStore的FragmentStateManager。 restoreAddedFragments恢复FragmentStore中的Fragment

  • 这个过程会依赖activity的事件分发

源码分析

Attach

activity的host赋值在, FragmentActivity 构造函数内部调用init

private void init() {
    addOnContextAvailableListener(new OnContextAvailableListener() {
        @Override
        public void onContextAvailable(@NonNull Context context) {
            mFragments.attachHost(null /*parent*/);
            Bundle savedInstanceState = getSavedStateRegistry()
                    .consumeRestoredStateForKey(FRAGMENTS_TAG);

            if (savedInstanceState != null) {
                Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);
                mFragments.restoreSaveState(p);
            }
        }
    });
}

fragment类型的host赋值在 父fragment performAttach的时候

void performAttach() {
    for (OnPreAttachedListener listener: mOnPreAttachedListeners) {
        listener.onPreAttached();
    }
    mOnPreAttachedListeners.clear();
    mChildFragmentManager.attachController(mHost, createFragmentContainer(), this);
    mState = ATTACHED;
    mCalled = false;
    onAttach(mHost.getContext());
    if (!mCalled) {
        throw new SuperNotCalledException("Fragment " + this
                + " did not call through to super.onAttach()");
    }
    mFragmentManager.dispatchOnAttachFragment(this);
    mChildFragmentManager.dispatchAttach();
}

expandOPs

Fragment expandOps(ArrayList<Fragment> added, Fragment oldPrimaryNav) {
    for (int opNum = 0; opNum < mOps.size(); opNum++) {
        final Op op = mOps.get(opNum);
        switch (op.mCmd) {
            case OP_ADD:
            case OP_ATTACH:
                added.add(op.mFragment);
                break;
            case OP_REMOVE:
            case OP_DETACH: {
                added.remove(op.mFragment);
                if (op.mFragment == oldPrimaryNav) {
                    mOps.add(opNum, new Op(OP_UNSET_PRIMARY_NAV, op.mFragment));
                    opNum++;
                    oldPrimaryNav = null;
                }
            }
            break;
            case OP_REPLACE: {
                final Fragment f = op.mFragment;
                final int containerId = f.mContainerId;
                boolean alreadyAdded = false;
                for (int i = added.size() - 1; i >= 0; i--) {
                    final Fragment old = added.get(i);
                    if (old.mContainerId == containerId) {
                        if (old == f) {
                            alreadyAdded = true;
                        } else {
                            // This is duplicated from above since we only make
                            // a single pass for expanding ops. Unset any outgoing primary nav.
                            if (old == oldPrimaryNav) {
                                mOps.add(opNum, new Op(OP_UNSET_PRIMARY_NAV, old));
                                opNum++;
                                oldPrimaryNav = null;
                            }
                            final Op removeOp = new Op(OP_REMOVE, old);
                            removeOp.mEnterAnim = op.mEnterAnim;
                            removeOp.mPopEnterAnim = op.mPopEnterAnim;
                            removeOp.mExitAnim = op.mExitAnim;
                            removeOp.mPopExitAnim = op.mPopExitAnim;
                            // old fragment和new fragment containerid一致,replace命令会先解析成remove + add
                            mOps.add(opNum, removeOp);
                            added.remove(old);
                            opNum++;
                        }
                    }
                }
                if (alreadyAdded) {
                    mOps.remove(opNum);
                    opNum--;
                } else {
                    op.mCmd = OP_ADD;
                    added.add(f);
                }
            }
            break;

        }
    }
    return oldPrimaryNav;
}

状态保存与恢复

FragmentManager.java

Parcelable saveAllState() {
    // Build list of currently added fragments.
    // 保存该宿主中所有的 添加过的 fragment
    ArrayList<String> added = mFragmentStore.saveAddedFragments();

    // Now save back stack.
    // 保存堆栈
    BackStackState[] backStack = null;
    if (mBackStack != null) {
        int size = mBackStack.size();
        if (size > 0) {
            backStack = new BackStackState[size];
            for (int i = 0; i < size; i++) {
                backStack[i] = new BackStackState(mBackStack.get(i));
                if (isLoggingEnabled(Log.VERBOSE)) {
                    Log.v(TAG, "saveAllState: adding back stack #" + i
                            + ": " + mBackStack.get(i));
                }
            }
        }
    }
    FragmentManagerState fms = new FragmentManagerState();
    fms.mActive = active;
    fms.mAdded = added;
    fms.mBackStack = backStack;
    fms.mBackStackIndex = mBackStackIndex.get();
    if (mPrimaryNav != null) {
        fms.mPrimaryNavActiveWho = mPrimaryNav.mWho;
    }
    // 参数
    fms.mResultKeys.addAll(mResults.keySet());
    fms.mResults.addAll(mResults.values());
    fms.mLaunchedFragments = new ArrayList<>(mLaunchedFragments);
    return fms;
}

void restoreSaveState(@Nullable Parcelable state) {
    // If there is no saved state at all, then there's nothing else to do
    if (state == null) return;
    FragmentManagerState fms = (FragmentManagerState) state;
    if (fms.mActive == null) return;
    // 可以理解为 恢复fragment需要的元数据
    for (FragmentState fs : fms.mActive) {
        if (fs != null) {
            FragmentStateManager fragmentStateManager;
            // 初始化 fragment 及 fragmentStateManager
             fragmentStateManager = new FragmentStateManager(mLifecycleCallbacksDispatcher,
                        mFragmentStore, mHost.getContext().getClassLoader(),
                        getFragmentFactory(), fs);
            Fragment f = fragmentStateManager.getFragment();
            f.mFragmentManager = this;
            if (isLoggingEnabled(Log.VERBOSE)) {
                Log.v(TAG, "restoreSaveState: active (" + f.mWho + "): " + f);
            }
            fragmentStateManager.restoreState(mHost.getContext().getClassLoader());
            mFragmentStore.makeActive(fragmentStateManager);
            // Catch the FragmentStateManager up to our current state
            // In almost all cases, this is Fragment.INITIALIZING, but just in
            // case a FragmentController does something...unique, let's do this anyways.
            fragmentStateManager.setFragmentManagerState(mCurState);
        }
    }
  
    // 通过FragmentState. 恢复 store里的added framgent列表
    mFragmentStore.restoreAddedFragments(fms.mAdded);

    // Build the back stack.
    if (fms.mBackStack != null) {
        mBackStack = new ArrayList<>(fms.mBackStack.length);
        for (int i = 0; i < fms.mBackStack.length; i++) {
            BackStackRecord bse = fms.mBackStack[i].instantiate(this);
            if (isLoggingEnabled(Log.VERBOSE)) {
                Log.v(TAG, "restoreAllState: back stack #" + i
                        + " (index " + bse.mIndex + "): " + bse);
                LogWriter logw = new LogWriter(TAG);
                PrintWriter pw = new PrintWriter(logw);
                bse.dump("  ", pw, false);
                pw.close();
            }
            mBackStack.add(bse);
        }
    } else {
        mBackStack = null;
    }
    mBackStackIndex.set(fms.mBackStackIndex);

    if (fms.mPrimaryNavActiveWho != null) {
        mPrimaryNav = findActiveFragment(fms.mPrimaryNavActiveWho);
        dispatchParentPrimaryNavigationFragmentChanged(mPrimaryNav);
    }

    ArrayList<String> savedResultKeys = fms.mResultKeys;
    if (savedResultKeys != null) {
        for (int i = 0; i < savedResultKeys.size(); i++) {
            Bundle savedResult = fms.mResults.get(i);
            savedResult.setClassLoader(mHost.getContext().getClassLoader());
            mResults.put(savedResultKeys.get(i), savedResult);
        }
    }
    mLaunchedFragments = new ArrayDeque<>(fms.mLaunchedFragments);
}

fragment初始化

FragmentStateManager.java -> instantiate

FragmentStateManager(@NonNull FragmentLifecycleCallbacksDispatcher dispatcher,
        @NonNull FragmentStore fragmentStore,
        @NonNull ClassLoader classLoader,
        @NonNull FragmentFactory fragmentFactory,
        @NonNull FragmentState fs) {
    mDispatcher = dispatcher;
    mFragmentStore = fragmentStore;
    mFragment = fragmentFactory.instantiate(classLoader, fs.mClassName);
    if (fs.mArguments != null) {
        fs.mArguments.setClassLoader(classLoader);
    }
    mFragment.setArguments(fs.mArguments);
    mFragment.mWho = fs.mWho;
    mFragment.mFromLayout = fs.mFromLayout;
    mFragment.mRestored = true;
    mFragment.mFragmentId = fs.mFragmentId;
    mFragment.mContainerId = fs.mContainerId;
    mFragment.mTag = fs.mTag;
    mFragment.mRetainInstance = fs.mRetainInstance;
    mFragment.mRemoving = fs.mRemoving;
    mFragment.mDetached = fs.mDetached;
    mFragment.mHidden = fs.mHidden;
    mFragment.mMaxState = Lifecycle.State.values()[fs.mMaxLifecycleState];
    if (fs.mSavedFragmentState != null) {
        mFragment.mSavedFragmentState = fs.mSavedFragmentState;
    } else {
        // When restoring a Fragment, always ensure we have a
        // non-null Bundle so that developers have a signal for
        // when the Fragment is being restored
        mFragment.mSavedFragmentState = new Bundle();
    }
    if (FragmentManager.isLoggingEnabled(Log.VERBOSE)) {
        Log.v(TAG, "Instantiated fragment " + mFragment);
    }
}

计算期待的状态

int computeExpectedState() {
    // If the FragmentManager is null, disallow changing the state at all
    if (mFragment.mFragmentManager == null) {
        return mFragment.mState;
    }
    // Assume the Fragment can go as high as the FragmentManager's state
    int maxState = mFragmentManagerState;

    // Don't allow the Fragment to go above its max lifecycle state
    switch (mFragment.mMaxState) {
        case RESUMED:
            // maxState can't go any higher than RESUMED, so there's nothing to do here
            break;
        case STARTED:
            maxState = Math.min(maxState, Fragment.STARTED);
            break;
        case CREATED:
            maxState = Math.min(maxState, Fragment.CREATED);
            break;
        case INITIALIZED:
            maxState = Math.min(maxState, Fragment.ATTACHED);
            break;
        default:
            maxState = Math.min(maxState, Fragment.INITIALIZING);
    }

    // For fragments that are created from a layout using the <fragment> tag (mFromLayout)
    if (mFragment.mFromLayout) {
        if (mFragment.mInLayout) {
            // Move them immediately to VIEW_CREATED when they are
            // actually added to the layout (mInLayout).
            maxState = Math.max(mFragmentManagerState, Fragment.VIEW_CREATED);
            // But don't move to higher than VIEW_CREATED until the view is added to its parent
            // and the LayoutInflater call has returned
            if (mFragment.mView != null && mFragment.mView.getParent() == null) {
                maxState = Math.min(maxState, Fragment.VIEW_CREATED);
            }
        } else {
            if (mFragmentManagerState < Fragment.ACTIVITY_CREATED) {
                // But while they are not in the layout, don't allow their
                // state to progress upward until the FragmentManager state
                // is at least ACTIVITY_CREATED. This ensures they get the onInflate()
                // callback before being attached or created.
                maxState = Math.min(maxState, mFragment.mState);
            } else {
                // Once the FragmentManager state is at least ACTIVITY_CREATED
                // their state can progress up to CREATED as we assume that
                // they are not ever going to be in layout
                maxState = Math.min(maxState, Fragment.CREATED);
            }
        }
    }
    // Fragments that are not currently added will sit in the CREATED state.
    if (!mFragment.mAdded) {
        // remove了fragment,需要状态降级
        maxState = Math.min(maxState, Fragment.CREATED);
    }
    SpecialEffectsController.Operation.LifecycleImpact awaitingEffect = null;
    if (FragmentManager.USE_STATE_MANAGER && mFragment.mContainer != null) {
        SpecialEffectsController controller = SpecialEffectsController.getOrCreateController(
                mFragment.mContainer, mFragment.getParentFragmentManager());
        awaitingEffect = controller.getAwaitingCompletionLifecycleImpact(this);
    }
    if (awaitingEffect == SpecialEffectsController.Operation.LifecycleImpact.ADDING) {
        // Fragments awaiting their enter effects cannot proceed beyond that state
        maxState = Math.min(maxState, Fragment.AWAITING_ENTER_EFFECTS);
    } else if (awaitingEffect == SpecialEffectsController.Operation.LifecycleImpact.REMOVING) {
        // Fragments that are in the process of being removed shouldn't go below that state
        maxState = Math.max(maxState, Fragment.AWAITING_EXIT_EFFECTS);
    } else if (mFragment.mRemoving) {
        if (mFragment.isInBackStack()) {
        // fragment放堆栈里,最低状态就是create
            // Fragments on the back stack shouldn't go higher than CREATED
            maxState = Math.min(maxState, Fragment.CREATED);
        } else {
            // 没有
            // While removing a fragment, we always move to INITIALIZING
            maxState = Math.min(maxState, Fragment.INITIALIZING);
        }
    }
    // Defer start if requested; don't allow it to move to STARTED or higher
    // if it's not already started.
    if (mFragment.mDeferStart && mFragment.mState < Fragment.STARTED) {
        maxState = Math.min(maxState, Fragment.ACTIVITY_CREATED);
    }
    if (FragmentManager.isLoggingEnabled(Log.VERBOSE)) {
        Log.v(FragmentManager.TAG, "computeExpectedState() of " + maxState + " for "
                + mFragment);
    }
    return maxState;
}

fragment中的命令

从下面函数中能窥探 fragment的命令及对应执行的代码:

void executeOps() {
    final int numOps = mOps.size();
    for (int opNum = 0; opNum < numOps; opNum++) {
        final Op op = mOps.get(opNum);
        final Fragment f = op.mFragment;
        if (f != null) {
            f.setPopDirection(false);
            f.setNextTransition(mTransition);
            f.setSharedElementNames(mSharedElementSourceNames, mSharedElementTargetNames);
        }
        switch (op.mCmd) {
            case OP_ADD:
                f.setAnimations(op.mEnterAnim, op.mExitAnim, op.mPopEnterAnim, op.mPopExitAnim);
                mManager.setExitAnimationOrder(f, false);
                mManager.addFragment(f);
                break;
            case OP_REMOVE:
                f.setAnimations(op.mEnterAnim, op.mExitAnim, op.mPopEnterAnim, op.mPopExitAnim);
                mManager.removeFragment(f);
                break;
            case OP_HIDE:
                f.setAnimations(op.mEnterAnim, op.mExitAnim, op.mPopEnterAnim, op.mPopExitAnim);
                mManager.hideFragment(f);
                break;
            case OP_SHOW:
                f.setAnimations(op.mEnterAnim, op.mExitAnim, op.mPopEnterAnim, op.mPopExitAnim);
                mManager.setExitAnimationOrder(f, false);
                mManager.showFragment(f);
                break;
            case OP_DETACH:
                f.setAnimations(op.mEnterAnim, op.mExitAnim, op.mPopEnterAnim, op.mPopExitAnim);
                mManager.detachFragment(f);
                break;
            case OP_ATTACH:
                f.setAnimations(op.mEnterAnim, op.mExitAnim, op.mPopEnterAnim, op.mPopExitAnim);
                mManager.setExitAnimationOrder(f, false);
                mManager.attachFragment(f);
                break;
            case OP_SET_PRIMARY_NAV:
                mManager.setPrimaryNavigationFragment(f);
                break;
            case OP_UNSET_PRIMARY_NAV:
                mManager.setPrimaryNavigationFragment(null);
                break;
            case OP_SET_MAX_LIFECYCLE:
                mManager.setMaxLifecycle(f, op.mCurrentMaxState);
                break;
            default:
                throw new IllegalArgumentException("Unknown cmd: " + op.mCmd);
        }
        if (!mReorderingAllowed && op.mCmd != OP_ADD && f != null) {
            if (!FragmentManager.USE_STATE_MANAGER) {
                mManager.moveFragmentToExpectedState(f);
            }
        }
    }
    if (!mReorderingAllowed && !FragmentManager.USE_STATE_MANAGER) {
        // Added fragments are added at the end to comply with prior behavior.
        mManager.moveToState(mManager.mCurState, true);
    }
}