理解 Fragment

理解 Fragment 的实现原理, FragmentTransaction 的事务机制等.

Fragment 的添加过程

使用如下代码:

setOnClickListener {
    with(supportFragmentManager) {
        beginTransaction()
            .add(R.id.fragment_container, MFragment.newInstance())
            .commit()
    }
}

方法调用栈:

Fragment Commit Flow

通过看调用栈中绿色的分布也能大致看出, 整个过程分了两个步骤.

对 Fragment 的操作需要先在 Activity 获取 FragmentManager, 那 FragmentManager 是从哪里拿到的呢?

FragmentManager 的创建

android.app.Activity 这个祖先类中的 getFragmentManager 方法已经 deprecated, 推荐我们用 android.support.v4.app.FragmentActivity#getSupportFragmentManager, 所以我们自己的 Activity 一般都继承了那些继承自 FragmentActivity 的 Activity(比如: AppCompatActivity).

FragmentActivity

androidx.fragment.app.FragmentActivity

FragmentActivity 的 getSupportFragmentManager:

public FragmentManager getSupportFragmentManager() {
    // 调用 mFragments 的方法
    return mFragments.getSupportFragmentManager();
}

mFragments 是 FragmentActivity 在内部构造的一个 FragmentController 类型的变量:

final FragmentController mFragments = FragmentController.createController(new HostCallbacks());

FragmentController

androidx.fragment.app.FragmentController

public static FragmentController createController(FragmentHostCallback<?> callbacks) {
    return new FragmentController(callbacks);
}

private FragmentController(FragmentHostCallback<?> callbacks) {
    mHost = callbacks;
}

// FragmentController 的 getSupportFragmentManager 方法是调用的其构造时传入的 callbacks
FragmentManager getSupportFragmentManager() {
    return mHost.mFragmentManager;
}

查看 FragmentController 内部的其他方法, 最后都是代理给 mHost 执行了. mHost 就是 FragmentActivity 在创建 FragmentController 时传入的 HostCallbacks.

HostCallbacks 是 FragmentActivity 的一个内部类, 其继承了 FragmentHostCallback:

HostCallbacks

androidx.fragment.app.FragmentActivity.HostCallbacks

class HostCallbacks extends FragmentHostCallback<FragmentActivity> implements ViewModelStoreOwner, OnBackPressedDispatcherOwner {
    public HostCallbacks() {
        super(FragmentActivity.this /*fragmentActivity*/);
    }
}

androidx.fragment.app.FragmentHostCallback

public abstract class FragmentHostCallback<E> extends FragmentContainer {
    private final Activity mActivity;
    private final Context mContext;
    private final Handler mHandler;
    private final int mWindowAnimations;

    // 创建 FragmentManager, 使用的是 FragmentManagerImpl
    final FragmentManager mFragmentManager = new FragmentManagerImpl();

    // HostCallbacks 中调用的是这个构造函数
    FragmentHostCallback(FragmentActivity activity) {
        this(activity, activity /*context*/, new Handler(), 0 /*windowAnimations*/);
    }

    FragmentHostCallback(Activity activity,Context context, Handler handler, int windowAnimations) {
        mActivity = activity;
        mContext = context;
        mHandler = handler;
        mWindowAnimations = windowAnimations;
    }
}

FragmentManagerImpl

androidx.fragment.app.FragmentManagerImpl

FragmentManagerImpl 继承了 FragmentManager, 自己没有特别的实现

class FragmentManagerImpl extends FragmentManager {
}

一图胜千言

概括图

至此, FragmentManager 的创建过程梳理结束, FragmentActivity 在创建时会创建一个 HostCallbacks 和 FragmentController, HostCallbacks 会在创建时创建 FragmentManager. FragmentController 会持有 HostCallbacks 对象的引用, 调用 FragmentController 的方法内部都将调用 HostCallbacks 对应的方法.


放大上面大图左侧的部分, 可以看addcommit 两个操作的调用栈:

add && commit

add 过程

整体调用栈:

FragmentManager: beginTransaction
    BackStackRecord: add -> doAddOp
        FragmentTransaction: doAddOp -> addOp

首先, FragmentManger 的 beginTransaction 方法返回了一个 BackStackRecord 对象

public FragmentTransaction beginTransaction() {
    return new BackStackRecord(this);
}

BackStackRecord

androidx.fragment.app.BackStackRecord

BackStackRecord 类继承自 FragmentTransaction, FragmentTransaction 是一个抽象类

// 构造函数
public BackStackRecord(FragmentManagerImpl manager) {
    mManager = manager;
}

比如调用 add(R.id.fragment_container, MFragment.newInstance())

// BackStackRecord 中没有实现该方法, 所以会调用父类 FragmentTransaction 的 add
public FragmentTransaction add(@IdRes int containerViewId, @NonNull Fragment fragment) {
    doAddOp(containerViewId, fragment, null, OP_ADD);
    return this;
}

// OP_ADD 是在 FragmentTransaction 中定义的一个常量, 看样子后面会用到**命令模式**.
// 其他类似常量
int OP_NULL = 0;
int OP_ADD = 1;
int OP_REPLACE = 2;
int OP_REMOVE = 3;
int OP_HIDE = 4;
int OP_SHOW = 5;
int OP_DETACH = 6;
int OP_ATTACH = 7;
int OP_SET_PRIMARY_NAV = 8;
int OP_UNSET_PRIMARY_NAV = 9;
int OP_SET_MAX_LIFECYCLE = 10;

接着 doAddOp:

// BackStackRecord 复写了 doAddOp, 所以会调用 BackStackRecord 自己实现的 doAddOp
void doAddOp(int containerViewId, Fragment fragment, @Nullable String tag, int opcmd) {
    // 调用父类的 doAddOp
    super.doAddOp(containerViewId, fragment, tag, opcmd);
    // 可见 Fragment 的 FragmentManager 是在这一步赋值的
    fragment.mFragmentManager = mManager;
}
// FragmentTransaction 的 doAddOp
void doAddOp(int containerViewId, Fragment fragment, @Nullable String tag, int opcmd) {
    final Class<?> fragmentClass = fragment.getClass();
    final int modifiers = fragmentClass.getModifiers();
    // 如果 fragment: 是匿名类 || 不是 public || 是内部类但不是静态的, 则抛出异常
    if (fragmentClass.isAnonymousClass() || !Modifier.isPublic(modifiers)
            || (fragmentClass.isMemberClass() && !Modifier.isStatic(modifiers))) {
        throw new IllegalStateException("Fragment " + fragmentClass.getCanonicalName() + "...");
    }

    if (tag != null) {
        // fragment 的 tag 指定之后不能修改
        if (fragment.mTag != null && !tag.equals(fragment.mTag)) {
            throw new IllegalStateException("Can't change tag of fragment");
        }
        fragment.mTag = tag;
    }

    if (containerViewId != 0) {
        if (containerViewId == View.NO_ID) {
            throw new IllegalArgumentException("Can't add fragment to container view with no id");
        }
        if (fragment.mFragmentId != 0 && fragment.mFragmentId != containerViewId) {
            throw new IllegalStateException("Can't change container ID of fragment ...");
        }
        fragment.mContainerId = fragment.mFragmentId = containerViewId;
    }

    // 构造一个 Op, 然后调用 addOp
    addOp(new Op(opcmd, fragment));
}
// FragmentTransaction addOp
void addOp(Op op) {
    // 将 op 添加到 mOps 中
    // mOps: 类型为 ArrayList<Op>, FragmentTransaction 的一个成员变量
    mOps.add(op);
    op.mEnterAnim = mEnterAnim;
    op.mExitAnim = mExitAnim;
    op.mPopEnterAnim = mPopEnterAnim;
    op.mPopExitAnim = mPopExitAnim;
}

一图胜千言

BackStackRecord ops

至此, add 调用过程结束, 会在 BackStackRecord 的 mOps 数组中添加一条 Op 记录, Op 记录着这次操作的命令(mCmd)和操作的 Fragment(mFragnment).

commit 过程

整体调用栈:

BackStackRecord: commit -> commitInternal
    FragmentManager: enqueueAction -> scheduleCommit
        HostCallBacks: getHandler.post

BackStackRecord

androidx.fragment.app.BackStackRecord#commit

public int commit() {
    // 参数为: boolean allowStateLoss
    return commitInternal(false);
}
enqueueAction

androidx.fragment.app.BackStackRecord#commitInternal

int commitInternal(boolean allowStateLoss) {
    if (mCommitted) throw new IllegalStateException("commit already called");
    mCommitted = true;
    // 如果在 commit 调用之前调用了 FragmentTransaction 的 addToBackStack, mAddToBackStack 就是 true, 否则 false
    if (mAddToBackStack) {
        mIndex = mManager.allocBackStackIndex();
    } else {
        mIndex = -1;
    }
    // FragmentManager#enququeAction
    // 第一个参数是 OpGenerator 类型
    mManager.enqueueAction(this, allowStateLoss);
    return mIndex;
}

BackStackRecord 实现了 OpGenrator 接口:

// 实现了 OpGenrator 接口的 generateOps 方法
public boolean generateOps(ArrayList<BackStackRecord> records, ArrayList<Boolean> isRecordPop) {
    // 将自己添加到 records 数组中
    records.add(this);
    isRecordPop.add(false);
    // 如果调用了 addToBackStack(), mAddToBackStack 就为 true
    if (mAddToBackStack) {
        // 将自己添加到 FragmentManager 的 mBackStack 数组中
        mManager.addBackStackState(this);
    }
    return true;
}

FragmentManager

androidx.fragment.app.FragmentManager#enqueueAction

void enqueueAction(OpGenerator action, boolean allowStateLoss) {
    //...
    synchronized (mPendingActions) {
        //...
        // 添加到等待队列中
        // mPendingActions: ArrayList<OpGenerator>
        mPendingActions.add(action);
        scheduleCommit();
    }
}

androidx.fragment.app.FragmentManager#scheduleCommit

void scheduleCommit() {
    synchronized (mPendingActions) {
        boolean postponeReady = mPostponedTransactions != null && !mPostponedTransactions.isEmpty();
        // 一次只能提交一个 OpGenerator(BackStackRecord), 上面在 commit 里会通过 mCommitted 标志做过滤
        boolean pendingReady = mPendingActions.size() == 1;
        if (postponeReady || pendingReady) {
            // mExecCommit: Runnable
            // 通过 Handler 向主线程 Looper 中发消息. 当消息被消费时, 会执行 mExecCommit
            mHost.getHandler().removeCallbacks(mExecCommit);
            mHost.getHandler().post(mExecCommit);
            updateOnBackPressedCallbackEnabled();
        }
    }
}

commit 调用之后, mExecCommit 这个 Runnable 就作为一个 Message 的 callback 插入到主线程 MessageQueue 中, 之后 mExecCommit 会从消息池中取出, 然后执行:

mExecCommit 被执行

private Runnable mExecCommit = new Runnable() {
    @Override
    public void run() {
        execPendingActions(true);
    }
};
execPendingActions
boolean execPendingActions(boolean allowStateLoss) {
    ensureExecReady(allowStateLoss);

    boolean didSomething = false;
    // 生成待处理操作
    while (generateOpsForPendingActions(mTmpRecords, mTmpIsPop)) {
        mExecutingActions = true;
        try {
            // 删除冗余操作并执行
            removeRedundantOperationsAndExecute(mTmpRecords, mTmpIsPop);
        } finally {
            cleanupExec();
        }
        didSomething = true;
    }

    updateOnBackPressedCallbackEnabled();
    doPendingDeferredStart();
    burpActive();

    return didSomething;
}

private void cleanupExec() {
    mExecutingActions = false;
    mTmpIsPop.clear();
    mTmpRecords.clear();
}
private boolean generateOpsForPendingActions(ArrayList<BackStackRecord> records, ArrayList<Boolean> isPop) {
    boolean didSomething = false;
    synchronized (mPendingActions) {
        if (mPendingActions.isEmpty()) {
            return false;
        }

        final int numActions = mPendingActions.size();
        for (int i = 0; i < numActions; i++) {
            // 将 mPendingActions 中的 actions, 通过调用 BackStackRecord 的 generateOps, 依次转移到 records
            didSomething |= mPendingActions.get(i).generateOps(records, isPop);
        }
        // 转移完成之后, 清空 mPendingActions
        mPendingActions.clear();
        // 执行完成之后, 移除 handler 中的回调
        mHost.getHandler().removeCallbacks(mExecCommit);
    }
    return didSomething;
}
private void removeRedundantOperationsAndExecute(ArrayList<BackStackRecord> records,
        ArrayList<Boolean> isRecordPop) {
    //...
    // Force start of any postponed transactions that interact with scheduled transactions:
    executePostponedTransaction(records, isRecordPop);

    final int numRecords = records.size();
    int startIndex = 0;
    for (int recordNum = 0; recordNum < numRecords; recordNum++) {
        // mReorderingAllowed: 可以通过 FragmentTransaction 的 setReorderingAllowed 设置为 ture
        final boolean canReorder = records.get(recordNum).mReorderingAllowed;
        // 默认 false
        if (!canReorder) {
            // ...
            executeOpsTogether(records, isRecordPop, recordNum, reorderingEnd);
            startIndex = reorderingEnd;
            recordNum = reorderingEnd - 1;
        }
    }
    // ...
}
 private void executeOpsTogether(ArrayList<BackStackRecord> records,
        ArrayList<Boolean> isRecordPop, int startIndex, int endIndex) {
    // ...
    executeOps(records, isRecordPop, startIndex, endIndex);
    // ...
}
executeOps
private static void executeOps(ArrayList<BackStackRecord> records,
        ArrayList<Boolean> isRecordPop, int startIndex, int endIndex) {
    for (int i = startIndex; i < endIndex; i++) {
        final BackStackRecord record = records.get(i);
        final boolean isPop = isRecordPop.get(i);
        // 这里是 add 操作, isPop 为 false
        if (isPop) {
            record.bumpBackStackNesting(-1);
            boolean moveToState = i == (endIndex - 1);
            record.executePopOps(moveToState);
        } else {
            // BackStackRecord#bumpBackStackNesting
            record.bumpBackStackNesting(1);
            // BackStackRecord#executeOps
            record.executeOps();
        }
    }
}

回到 BackStackRecord:

androidx.fragment.app.BackStackRecord#executeOps

void executeOps() {
    final int numOps = mOps.size();
    for (int opNum = 0; opNum < numOps; opNum++) {
        final Op op = mOps.get(opNum);
        final Fragment f = op.fragment;
        if (f != null) {
            f.setNextTransition(mTransition, mTransitionStyle);
        }
        // 执行不同命令
        switch (op.cmd) {
            case OP_ADD:
                f.setNextAnim(op.enterAnim);
                mManager.addFragment(f, false);
                break;
            case OP_REMOVE:
            //...
            case OP_HIDE:
            //...
            case OP_SHOW:
            //...
            case OP_DETACH:
            //...
            case OP_ATTACH:
            //...
        }
    }
    if (!mReorderingAllowed) {
        // 将 Fragment 切到当前状态
        mManager.moveToState(mManager.mCurState, true);
    }
}
addFragment
public void addFragment(Fragment fragment, boolean moveToStateNow) {
    if (DEBUG) Log.v(TAG, "add: " + fragment);
    makeActive(fragment);
    if (!fragment.mDetached) {
        // 不能重复添加同一个 Fragment
        if (mAdded.contains(fragment)) {
            throw new IllegalStateException("Fragment already added: " + fragment);
        }
        synchronized (mAdded) {
            // Fragment 添加到 mAdded 数组中
            mAdded.add(fragment);
        }
        fragment.mAdded = true;
        fragment.mRemoving = false;
        if (fragment.mView == null) {
            fragment.mHiddenChanged = false;
        }
        if (moveToStateNow) {
            moveToState(fragment);
        }
    }
}
makeActive
void makeActive(Fragment f) {
    // Fragment 的 mIndex 变量初始值为 -1
    if (f.mIndex >= 0) {
        return;
    }
    f.setIndex(mNextFragmentIndex++, mParent);
    if (mActive == null) {
        mActive = new SparseArray<>();
    }
    // Fragment 添加到 mActive Map 中
    mActive.put(f.mIndex, f);
}
moveToState
void moveToState(int newState, boolean always) {
    //...
    mCurState = newState;
    if (mActive != null) {
        final int numAdded = mAdded.size();
        for (int i = 0; i < numAdded; i++) {
            Fragment f = mAdded.get(i);
            moveFragmentToExpectedState(f);
        }
        //...
    }
}
void moveFragmentToExpectedState(Fragment f) {
    if (f == null) {
        return;
    }
    int nextState = mCurState;
    // addFragment 时, f.mRemoving 赋值为 false
    if (f.mRemoving) {
        if (f.isInBackStack()) {
            nextState = Math.min(nextState, Fragment.CREATED);
        } else {
            nextState = Math.min(nextState, Fragment.INITIALIZING);
        }
    }
    // 真正开始切换状态
    moveToState(f, nextState, f.getNextTransition(), f.getNextTransitionStyle(), false);
    //...
}

moveState 方法有300行代码 🤦‍♂️

    void moveToState(Fragment f, int newState, int transit, int transitionStyle,
            boolean keepActive) {
        // Fragments that are not currently added will sit in the onCreate() state.
        if ((!f.mAdded || f.mDetached) && newState > Fragment.CREATED) {
            newState = Fragment.CREATED;
        }
        if (f.mRemoving && newState > f.mState) {
            if (f.mState == Fragment.INITIALIZING && f.isInBackStack()) {
                // Allow the fragment to be created so that it can be saved later.
                newState = Fragment.CREATED;
            } else {
                // While removing a fragment, we can't change it to a higher state.
                newState = f.mState;
            }
        }
        // Defer start if requested; don't allow it to move to STARTED or higher
        // if it's not already started.
        if (f.mDeferStart && f.mState < Fragment.STARTED && newState > Fragment.ACTIVITY_CREATED) {
            newState = Fragment.ACTIVITY_CREATED;
        }
        if (f.mState <= newState) {
            // For fragments that are created from a layout, when restoring from
            // state we don't want to allow them to be created until they are
            // being reloaded from the layout.
            if (f.mFromLayout && !f.mInLayout) {
                return;
            }
            if (f.getAnimatingAway() != null || f.getAnimator() != null) {
                // The fragment is currently being animated...  but!  Now we
                // want to move our state back up.  Give up on waiting for the
                // animation, move to whatever the final state should be once
                // the animation is done, and then we can proceed from there.
                f.setAnimatingAway(null);
                f.setAnimator(null);
                moveToState(f, f.getStateAfterAnimating(), 0, 0, true);
            }
            switch (f.mState) {
                case Fragment.INITIALIZING:
                    if (newState > Fragment.INITIALIZING) {
                        if (DEBUG) Log.v(TAG, "moveto CREATED: " + f);
                        if (f.mSavedFragmentState != null) {
                            f.mSavedFragmentState.setClassLoader(mHost.getContext()
                                    .getClassLoader());
                            f.mSavedViewState = f.mSavedFragmentState.getSparseParcelableArray(
                                    FragmentManagerImpl.VIEW_STATE_TAG);
                            f.mTarget = getFragment(f.mSavedFragmentState,
                                    FragmentManagerImpl.TARGET_STATE_TAG);
                            if (f.mTarget != null) {
                                f.mTargetRequestCode = f.mSavedFragmentState.getInt(
                                        FragmentManagerImpl.TARGET_REQUEST_CODE_STATE_TAG, 0);
                            }
                            if (f.mSavedUserVisibleHint != null) {
                                f.mUserVisibleHint = f.mSavedUserVisibleHint;
                                f.mSavedUserVisibleHint = null;
                            } else {
                                f.mUserVisibleHint = f.mSavedFragmentState.getBoolean(
                                        FragmentManagerImpl.USER_VISIBLE_HINT_TAG, true);
                            }
                            if (!f.mUserVisibleHint) {
                                f.mDeferStart = true;
                                if (newState > Fragment.ACTIVITY_CREATED) {
                                    newState = Fragment.ACTIVITY_CREATED;
                                }
                            }
                        }

                        f.mHost = mHost;
                        f.mParentFragment = mParent;
                        f.mFragmentManager = mParent != null
                                ? mParent.mChildFragmentManager : mHost.getFragmentManagerImpl();

                        // If we have a target fragment, push it along to at least CREATED
                        // so that this one can rely on it as an initialized dependency.
                        if (f.mTarget != null) {
                            if (mActive.get(f.mTarget.mIndex) != f.mTarget) {
                                throw new IllegalStateException("Fragment " + f
                                        + " declared target fragment " + f.mTarget
                                        + " that does not belong to this FragmentManager!");
                            }
                            if (f.mTarget.mState < Fragment.CREATED) {
                                moveToState(f.mTarget, Fragment.CREATED, 0, 0, true);
                            }
                        }

                        dispatchOnFragmentPreAttached(f, mHost.getContext(), false);
                        f.mCalled = false;
                        f.onAttach(mHost.getContext());
                        if (!f.mCalled) {
                            throw new SuperNotCalledException("Fragment " + f
                                    + " did not call through to super.onAttach()");
                        }
                        if (f.mParentFragment == null) {
                            mHost.onAttachFragment(f);
                        } else {
                            f.mParentFragment.onAttachFragment(f);
                        }
                        dispatchOnFragmentAttached(f, mHost.getContext(), false);

                        if (!f.mIsCreated) {
                            dispatchOnFragmentPreCreated(f, f.mSavedFragmentState, false);
                            f.performCreate(f.mSavedFragmentState);
                            dispatchOnFragmentCreated(f, f.mSavedFragmentState, false);
                        } else {
                            f.restoreChildFragmentState(f.mSavedFragmentState);
                            f.mState = Fragment.CREATED;
                        }
                        f.mRetaining = false;
                    }
                    // fall through
                case Fragment.CREATED:
                    // This is outside the if statement below on purpose; we want this to run
                    // even if we do a moveToState from CREATED => *, CREATED => CREATED, and
                    // * => CREATED as part of the case fallthrough above.
                    ensureInflatedFragmentView(f);

                    if (newState > Fragment.CREATED) {
                        if (DEBUG) Log.v(TAG, "moveto ACTIVITY_CREATED: " + f);
                        if (!f.mFromLayout) {
                            ViewGroup container = null;
                            if (f.mContainerId != 0) {
                                if (f.mContainerId == View.NO_ID) {
                                    throwException(new IllegalArgumentException(
                                            "Cannot create fragment "
                                                    + f
                                                    + " for a container view with no id"));
                                }
                                container = (ViewGroup) mContainer.onFindViewById(f.mContainerId);
                                if (container == null && !f.mRestored) {
                                    String resName;
                                    try {
                                        resName = f.getResources().getResourceName(f.mContainerId);
                                    } catch (NotFoundException e) {
                                        resName = "unknown";
                                    }
                                    throwException(new IllegalArgumentException(
                                            "No view found for id 0x"
                                            + Integer.toHexString(f.mContainerId) + " ("
                                            + resName
                                            + ") for fragment " + f));
                                }
                            }
                            f.mContainer = container;
                            f.performCreateView(f.performGetLayoutInflater(
                                    f.mSavedFragmentState), container, f.mSavedFragmentState);
                            if (f.mView != null) {
                                f.mInnerView = f.mView;
                                f.mView.setSaveFromParentEnabled(false);
                                if (container != null) {
                                    container.addView(f.mView);
                                }
                                if (f.mHidden) {
                                    f.mView.setVisibility(View.GONE);
                                }
                                f.onViewCreated(f.mView, f.mSavedFragmentState);
                                dispatchOnFragmentViewCreated(f, f.mView, f.mSavedFragmentState,
                                        false);
                                // Only animate the view if it is visible. This is done after
                                // dispatchOnFragmentViewCreated in case visibility is changed
                                f.mIsNewlyAdded = (f.mView.getVisibility() == View.VISIBLE)
                                        && f.mContainer != null;
                            } else {
                                f.mInnerView = null;
                            }
                        }

                        f.performActivityCreated(f.mSavedFragmentState);
                        dispatchOnFragmentActivityCreated(f, f.mSavedFragmentState, false);
                        if (f.mView != null) {
                            f.restoreViewState(f.mSavedFragmentState);
                        }
                        f.mSavedFragmentState = null;
                    }
                    // fall through
                case Fragment.ACTIVITY_CREATED:
                    if (newState > Fragment.ACTIVITY_CREATED) {
                        if (DEBUG) Log.v(TAG, "moveto STARTED: " + f);
                        f.performStart();
                        dispatchOnFragmentStarted(f, false);
                    }
                    // fall through
                case Fragment.STARTED:
                    if (newState > Fragment.STARTED) {
                        if (DEBUG) Log.v(TAG, "moveto RESUMED: " + f);
                        f.performResume();
                        dispatchOnFragmentResumed(f, false);
                        f.mSavedFragmentState = null;
                        f.mSavedViewState = null;
                    }
            }
        } else if (f.mState > newState) {
            switch (f.mState) {
                case Fragment.RESUMED:
                    if (newState < Fragment.RESUMED) {
                        if (DEBUG) Log.v(TAG, "movefrom RESUMED: " + f);
                        f.performPause();
                        dispatchOnFragmentPaused(f, false);
                    }
                    // fall through
                case Fragment.STARTED:
                    if (newState < Fragment.STARTED) {
                        if (DEBUG) Log.v(TAG, "movefrom STARTED: " + f);
                        f.performStop();
                        dispatchOnFragmentStopped(f, false);
                    }
                    // fall through
                case Fragment.ACTIVITY_CREATED:
                    if (newState < Fragment.ACTIVITY_CREATED) {
                        if (DEBUG) Log.v(TAG, "movefrom ACTIVITY_CREATED: " + f);
                        if (f.mView != null) {
                            // Need to save the current view state if not
                            // done already.
                            if (mHost.onShouldSaveFragmentState(f) && f.mSavedViewState == null) {
                                saveFragmentViewState(f);
                            }
                        }
                        f.performDestroyView();
                        dispatchOnFragmentViewDestroyed(f, false);
                        if (f.mView != null && f.mContainer != null) {
                            // Stop any current animations:
                            f.mContainer.endViewTransition(f.mView);
                            f.mView.clearAnimation();
                            AnimationOrAnimator anim = null;
                            if (mCurState > Fragment.INITIALIZING && !mDestroyed
                                    && f.mView.getVisibility() == View.VISIBLE
                                    && f.mPostponedAlpha >= 0) {
                                anim = loadAnimation(f, transit, false,
                                        transitionStyle);
                            }
                            f.mPostponedAlpha = 0;
                            if (anim != null) {
                                animateRemoveFragment(f, anim, newState);
                            }
                            f.mContainer.removeView(f.mView);
                        }
                        f.mContainer = null;
                        f.mView = null;
                        // Set here to ensure that Observers are called after
                        // the Fragment's view is set to null
                        f.mViewLifecycleOwner = null;
                        f.mViewLifecycleOwnerLiveData.setValue(null);
                        f.mInnerView = null;
                        f.mInLayout = false;
                    }
                    // fall through
                case Fragment.CREATED:
                    if (newState < Fragment.CREATED) {
                        if (mDestroyed) {
                            // The fragment's containing activity is
                            // being destroyed, but this fragment is
                            // currently animating away.  Stop the
                            // animation right now -- it is not needed,
                            // and we can't wait any more on destroying
                            // the fragment.
                            if (f.getAnimatingAway() != null) {
                                View v = f.getAnimatingAway();
                                f.setAnimatingAway(null);
                                v.clearAnimation();
                            } else if (f.getAnimator() != null) {
                                Animator animator = f.getAnimator();
                                f.setAnimator(null);
                                animator.cancel();
                            }
                        }
                        if (f.getAnimatingAway() != null || f.getAnimator() != null) {
                            // We are waiting for the fragment's view to finish
                            // animating away.  Just make a note of the state
                            // the fragment now should move to once the animation
                            // is done.
                            f.setStateAfterAnimating(newState);
                            newState = Fragment.CREATED;
                        } else {
                            if (DEBUG) Log.v(TAG, "movefrom CREATED: " + f);
                            if (!f.mRetaining) {
                                f.performDestroy();
                                dispatchOnFragmentDestroyed(f, false);
                            } else {
                                f.mState = Fragment.INITIALIZING;
                            }

                            f.performDetach();
                            dispatchOnFragmentDetached(f, false);
                            if (!keepActive) {
                                if (!f.mRetaining) {
                                    makeInactive(f);
                                } else {
                                    f.mHost = null;
                                    f.mParentFragment = null;
                                    f.mFragmentManager = null;
                                }
                            }
                        }
                    }
            }
        }

        if (f.mState != newState) {
            Log.w(TAG, "moveToState: Fragment state for " + f + " not updated inline; "
                    + "expected state " + newState + " found " + f.mState);
            f.mState = newState;
        }
    }