AndroidX Fragment 生命周期调度分析

563 阅读3分钟

本文基于androidx.fragment:fragment:1.5.4分析

先抛出问题:

1. fragment 生命周期到底是如何调度的?

2. add/replace show/hide remove addToBackStack ...... 各种事务的操作符到底对fragment生命周期有着怎样的影响呢?

fragment 调度的主要流程

fragment.png

接下来关注最重要的方法 executeOpsTogether

private void executeOpsTogether(@NonNull ArrayList<BackStackRecord> records,
        @NonNull ArrayList<Boolean> isRecordPop, int startIndex, int endIndex) {
    // 第一步: 拆解操作
    ...
    if (!isPop) {
        oldPrimaryNav = record.expandOps(mTmpAddedFragments, oldPrimaryNav);
    } else {
        oldPrimaryNav = record.trackAddedFragmentsInPop(mTmpAddedFragments, oldPrimaryNav);
    }
    ...

    // 第二步: 执行相关的fragment相关操作 根据cmdOp执行mManager.showFragment(f)等操作
    executeOps(records, isRecordPop, startIndex, endIndex);
    
    // 第三步:调度生命周期
    // 1. 调度生命周期     
    //    moveToExpectedState 中 
    //           case Fragment.ACTIVITY_CREATED
    //           case Fragment.AWAITING_EXIT_EFFECTS
    //    会添加 SpecialEffectsController 辅助调度生命周期
    ...
    fragmentStateManager.moveToExpectedState();
    ...
    
    // 2. 辅助调度生命周期, 该方法中最终会调用到 fragmentStateManager.moveToExpectedState();
    ...
    controller.executePendingOperations();
    ...
}

expandOps

解析操作符是在BackStackRecord中的expandOps方法中

我们主要关注的是 
OP_ADD OP_ATTACH
OP_REMOVE OP_DETACH
OP_REPLACE 会将 操作分解为两步,
    1. 旧fragment的remove
    2. 新fragment的add
这几个操作会影响fragment的生命周期

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 {
                            if (old == oldPrimaryNav) {
                                mOps.add(opNum, new Op(OP_UNSET_PRIMARY_NAV, old, true));
                                opNum++;
                                oldPrimaryNav = null;
                            }
                            final Op removeOp = new Op(OP_REMOVE, old, true);
                            removeOp.mEnterAnim = op.mEnterAnim;
                            removeOp.mPopEnterAnim = op.mPopEnterAnim;
                            removeOp.mExitAnim = op.mExitAnim;
                            removeOp.mPopExitAnim = op.mPopExitAnim;
                            mOps.add(opNum, removeOp);
                            added.remove(old);
                            opNum++;
                        }
                    }
                }
                if (alreadyAdded) {
                    mOps.remove(opNum);
                    opNum--;
                } else {
                    op.mCmd = OP_ADD;
                    op.mFromExpandedOp = true;
                    added.add(f);
                }
            }
            break;
            case OP_SET_PRIMARY_NAV: {       
                mOps.add(opNum, new Op(OP_UNSET_PRIMARY_NAV, oldPrimaryNav, true));
                op.mFromExpandedOp = true;
                opNum++;        
                oldPrimaryNav = op.mFragment;
            }
            break;
        }
    }
    return oldPrimaryNav;
}

executeOps

record.bumpBackStackNesting 这个方法的关注点在于: 
    改变了fragment 中的mBackStackNesting属性的值, 这个是会影响fragment的生命周期执行的

record.executeOps这个方法的关注点在于: 
    case OP_HIDE
    case OP_SHOW
会改变fragment的mHiddenChanged和mHidden属性的值

private static void executeOps(@NonNull ArrayList<BackStackRecord> records,
        @NonNull 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);
        if (isPop) {
            record.bumpBackStackNesting(-1);
            record.executePopOps();
        } else {
            record.bumpBackStackNesting(1);
            record.executeOps();
        }
    }
}

// 这里很重要,改变了fragment 中的mBackStackNesting属性的值
void bumpBackStackNesting(int amt) {
    if (!mAddToBackStack) {
        return;
    }
    if (FragmentManager.isLoggingEnabled(Log.VERBOSE)) {
        Log.v(TAG, "Bump nesting in " + this + " by " + amt);
    }
    final int numOps = mOps.size();
    for (int opNum = 0; opNum < numOps; opNum++) {
        final Op op = mOps.get(opNum);
        if (op.mFragment != null) {
            op.mFragment.mBackStackNesting += amt;
            if (FragmentManager.isLoggingEnabled(Log.VERBOSE)) {
                Log.v(TAG, "Bump nesting of "
                        + op.mFragment + " to " + op.mFragment.mBackStackNesting);
            }
        }
    }
}

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.mBeingSaved = mBeingSaved;
            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);
        }
    }
}

moveToExpectedState

这个方法的源代码很长,我们可以关注重点:
moveToExpectedState 中while循环退出的条件就是 computeExpectedState 返回值 和 mFragment.mState相等

moveToExpectedState中重点在于:
    case Fragment.ACTIVITY_CREATED
    case Fragment.AWAITING_EXIT_EFFECTS
这两个case往SpecialEffectsController中加入了相关操作

maxState 是关键,控制 moveToExpectedState 退出循环的

mFragment.isInBackStack() 重点,这个方法决定了fragment的生命周期是否执行onDestroyView后面的生命周期方法

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) {
        maxState = Math.min(maxState, Fragment.CREATED);
    }
    
    // 
    SpecialEffectsController.Operation.LifecycleImpact awaitingEffect = null;
    if (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
        // 这里控制fragment走resume生命周期方法
        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) {
        // 这里会控制 fragment 是否走 detach 生命周期方法
        if (mFragment.isInBackStack()) {
            // 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;
}


void moveToExpectedState() {
    if (mMovingToState) {
        if (FragmentManager.isLoggingEnabled(Log.VERBOSE)) {
            Log.v(FragmentManager.TAG, "Ignoring re-entrant call to "
                    + "moveToExpectedState() for " + getFragment());
        }
        return;
    }
    try {
        mMovingToState = true;

        boolean stateWasChanged = false;
        int newState;
        while ((newState = computeExpectedState()) != mFragment.mState) {
            stateWasChanged = true;
            if (newState > mFragment.mState) {
                // Moving upward
                int nextStep = mFragment.mState + 1;
                switch (nextStep) {
                    case Fragment.ATTACHED:
                        attach();
                        break;
                    case Fragment.CREATED:
                        create();
                        break;
                    case Fragment.VIEW_CREATED:
                        ensureInflatedView();
                        createView();
                        break;
                    case Fragment.AWAITING_EXIT_EFFECTS:
                        activityCreated();
                        break;
                    case Fragment.ACTIVITY_CREATED:
                        if (mFragment.mView != null && mFragment.mContainer != null) {
                            SpecialEffectsController controller = SpecialEffectsController
                                    .getOrCreateController(mFragment.mContainer,
                                            mFragment.getParentFragmentManager());
                            int visibility = mFragment.mView.getVisibility();
                            SpecialEffectsController.Operation.State finalState =
                                    SpecialEffectsController.Operation.State.from(visibility);
                                    
                            // 加入该操作,是为后面执行 fragment 的resume 生命周期方法
                            controller.enqueueAdd(finalState, this);
                        }
                        mFragment.mState = Fragment.ACTIVITY_CREATED;
                        break;
                    case Fragment.STARTED:
                        start();
                        break;
                    case Fragment.AWAITING_ENTER_EFFECTS:
                        mFragment.mState = Fragment.AWAITING_ENTER_EFFECTS;
                        break;
                    case Fragment.RESUMED:
                        resume();
                        break;
                }
            } else {
                // Moving downward
                int nextStep = mFragment.mState - 1;
                switch (nextStep) {
                    case Fragment.AWAITING_ENTER_EFFECTS:
                        pause();
                        break;
                    case Fragment.STARTED:
                        mFragment.mState = Fragment.STARTED;
                        break;
                    case Fragment.ACTIVITY_CREATED:
                        stop();
                        break;
                    case Fragment.AWAITING_EXIT_EFFECTS:
                        if (FragmentManager.isLoggingEnabled(Log.DEBUG)) {
                            Log.d(TAG, "movefrom ACTIVITY_CREATED: " + mFragment);
                        }
                        if (mFragment.mBeingSaved) {
                            saveState();
                        } else if (mFragment.mView != null) {
                            // Need to save the current view state if not done already
                            // by saveInstanceState()
                            if (mFragment.mSavedViewState == null) {
                                saveViewState();
                            }
                        }
                        if (mFragment.mView != null && mFragment.mContainer != null) {
                            SpecialEffectsController controller = SpecialEffectsController
                                    .getOrCreateController(mFragment.mContainer,
                                            mFragment.getParentFragmentManager());
                            // 加入该操作,是为后面执行 旧fragment 执行 destroyView ----- detach 等生命周期方法
                            // 执行完 destroyView 后,是否执行后面的生命周期方法取决于当前回退栈中是否有fragment,
                            // 没有则往后面执行,否则停止     
                            controller.enqueueRemove(this);
                        }
                        mFragment.mState = Fragment.AWAITING_EXIT_EFFECTS;
                        break;
                    case Fragment.VIEW_CREATED:
                        mFragment.mInLayout = false;
                        mFragment.mState = Fragment.VIEW_CREATED;
                        break;
                    case Fragment.CREATED:
                        destroyFragmentView();
                        mFragment.mState = Fragment.CREATED;
                        break;
                    case Fragment.ATTACHED:
                        if (mFragment.mBeingSaved
                                && mFragmentStore.getSavedState(mFragment.mWho) == null) {
                            saveState();
                        }
                        destroy();
                        break;
                    case Fragment.INITIALIZING:
                        detach();
                        break;
                }
            }
        }
        if (!stateWasChanged && mFragment.mState == Fragment.INITIALIZING) {
            // If the state wasn't changed and the Fragment should be removed
            // then we need to do the work of destroy()+detach() here
            // to ensure the FragmentManager is in a cleaned up state
            if (mFragment.mRemoving && !mFragment.isInBackStack() && !mFragment.mBeingSaved) {
                if (FragmentManager.isLoggingEnabled(Log.DEBUG)) {
                    Log.d(TAG, "Cleaning up state of never attached fragment: " + mFragment);
                }
                mFragmentStore.getNonConfig().clearNonConfigState(mFragment);
                mFragmentStore.makeInactive(this);
                if (FragmentManager.isLoggingEnabled(Log.DEBUG)) {
                    Log.d(TAG, "initState called for fragment: " + mFragment);
                }
                mFragment.initState();
            }
        }
        // show / hide 调度 fragment 的 onHiddenChanged 方法,这两个命令不会影响fragment的生命周期
        if (mFragment.mHiddenChanged) {
            if (mFragment.mView != null && mFragment.mContainer != null) {
                // Get the controller and enqueue the show/hide
                SpecialEffectsController controller = SpecialEffectsController
                        .getOrCreateController(mFragment.mContainer,
                                mFragment.getParentFragmentManager());
                if (mFragment.mHidden) {
                    controller.enqueueHide(this);
                } else {
                    controller.enqueueShow(this);
                }
            }
            if (mFragment.mFragmentManager != null) {
                mFragment.mFragmentManager.invalidateMenuForFragment(mFragment);
            }
            mFragment.mHiddenChanged = false;
            mFragment.onHiddenChanged(mFragment.mHidden);
            mFragment.mChildFragmentManager.dispatchOnHiddenChanged();
        }
    } finally {
        mMovingToState = false;
    }
}

总结

add/replace/remove  会影响生命周期
show/hide 不会影响生命周期,只会调用 onHiddenChanged方法
addToBackStack 这个是会影响生命周期的