Android Fragment浅析

基本使用

Fragment的使用一般涉及到两个类:FragmentManagerFragmentTransaction

val fragmentManager = supportFragmentManager
val fragmentTransaction = fragmentManager.beginTransaction()

可使用 FragmentManager 执行的操作包括:

  • 通过 findFragmentById()findFragmentByTag()获取 Activity 中存在的片段。
  • 通过 popBackStack()(模拟用户发出的返回命令)使片段从返回栈中弹出。
  • 通过 addOnBackStackChangedListener() 注册侦听返回栈变化的侦听器。

可以从 FragmentManager 获取一个 FragmentTransaction 实例,然后使用 add()remove()replace() 等方法,为给定事务设置您想要执行的所有更改。然后,如要将事务应用到 Activity,您必须调用 commit()

val newFragment = ExampleFragment()
val transaction = supportFragmentManager.beginTransaction()
transaction.replace(R.id.fragment_container, newFragment)
transaction.addToBackStack(null)
transaction.commit()

源码分析

FragmentController

MainActivity:AppCompatActivity:FragmentActivity。在FragmentActivity中有一个常量叫mFragments。

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

这是一个FragmentController对象。FragmentController,听名字是一个控制类,看来应该是用来控制Fragment的,其内部持有一个FragmentHostCallback类型的对象mHost。

public class FragmentController {
    private final FragmentHostCallback<?> mHost;
    ...
    //下面都是类似这样的代码:
    public XX FunXX () {
        return mHost.mFragmentManager.FunXX();
    }
    //比如:
    public void attachHost(@Nullable Fragment parent) {
        mHost.mFragmentManager.attachController(mHost, mHost /*container*/, parent);
    }
}

扫一眼这个控制类下面的方法,基本上都是调用的mHost.mFragmentManager.XX( )方法,所以我们判断FragmentController类又是个空壳子,其类目的方法全在mHost的mFragmentManager对象中实现。

所以我们理所当然的打开FragmentHostCallback,发现里面持有这样几个对象。

public abstract class FragmentHostCallback<E> extends FragmentContainer {
    private final Activity mActivity;
    private final Context mContext;
    private final Handler mHandler;
    private final int mWindowAnimations;
    final FragmentManager mFragmentManager = new FragmentManagerImpl();
    ...
}

FragmentManager是个常量,我们没有调用任何代码ta就在这里自己创建了。得到这个信息就够了,然后我们看自己调用的代码。

wait...

对了,还有一个地方要看一眼,在FragmentActivity的onCreate方法中,有一行mFragments.attachHost(null /parent/)**;去到FragmentManager中看:

void attachController(@NonNull FragmentHostCallback<?> host,
        @NonNull FragmentContainer container, @Nullable final Fragment parent) {
    if (mHost != null) throw new IllegalStateException("Already attached");
    mHost = host;
    mContainer = container;
    mParent = parent;
    if (mParent != null) {
        // Since the callback depends on us being the primary navigation fragment,
        // update our callback now that we have a parent so that we have the correct
        // state by default
        updateOnBackPressedCallbackEnabled();
    }
    // Set up the OnBackPressedCallback
    if (host instanceof OnBackPressedDispatcherOwner) {
        OnBackPressedDispatcherOwner dispatcherOwner = ((OnBackPressedDispatcherOwner) host);
        mOnBackPressedDispatcher = dispatcherOwner.getOnBackPressedDispatcher();
        LifecycleOwner owner = parent != null ? parent : dispatcherOwner;
        mOnBackPressedDispatcher.addCallback(owner, mOnBackPressedCallback);
    }

    // Get the FragmentManagerViewModel
    if (parent != null) {
        mNonConfig = parent.mFragmentManager.getChildNonConfig(parent);
    } else if (host instanceof ViewModelStoreOwner) {
        ViewModelStore viewModelStore = ((ViewModelStoreOwner) host).getViewModelStore();
        mNonConfig = FragmentManagerViewModel.getInstance(viewModelStore);
    } else {
        mNonConfig = new FragmentManagerViewModel(false);
    }
}

给FragmentManager传了一些值进去,包括mHost,mParent等。mHost就是FragmentHostCallback。

FragmentManager

好了,现在我们自己在调用getSupportFragmentManager()方法时,返回的就是我们刚刚看到的mFragmentManager,也是创建FragmentControl时带入的HostCallbacks。

//-----------FragmentActivity.java-------------
public FragmentManager getSupportFragmentManager() {
    return mFragments.getSupportFragmentManager();
}
//-----------FragmentControl.java-----------------
public FragmentManager getSupportFragmentManager() {
    return mHost.mFragmentManager;
}

所以beginTransaction自然要去FragmentManager类下面去找了。

beginTransaction

public FragmentTransaction beginTransaction() {
    return new BackStackRecord(this);//this就是FragmentManager呐。
}

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

final class BackStackRecord extends FragmentTransaction implements FragmentManager.BackStackEntry, FragmentManager.OpGenerator {
    ...
}

所以我们一般调用add、show、hide、replace等操作时,实际是调用的FragmentTransaction中的方法。以add方法为例:

add(containerViewId,fragment)

public abstract class FragmentTransaction {
    public FragmentTransaction add(@IdRes int containerViewId, @NonNull Fragment fragment) {
        doAddOp(containerViewId, fragment, null, OP_ADD);
        return this;
    }
    
    void doAddOp(int containerViewId, Fragment fragment, @Nullable String tag, int opcmd) {
        final Class<?> fragmentClass = fragment.getClass();
        final int modifiers = fragmentClass.getModifiers();
        if (fragmentClass.isAnonymousClass() || !Modifier.isPublic(modifiers)
                || (fragmentClass.isMemberClass() && !Modifier.isStatic(modifiers))) {
            throw new IllegalStateException("Fragment " + fragmentClass.getCanonicalName()
                    + " must be a public static class to be  properly recreated from"
                    + " instance state.");
        }

        if (tag != null) {
            if (fragment.mTag != null && !tag.equals(fragment.mTag)) {
                throw new IllegalStateException("Can't change tag of fragment "
                        + fragment + ": was " + fragment.mTag
                        + " now " + tag);
            }
            fragment.mTag = tag;
        }

        //---------------------存储containerViewId到fragment中--------------
        if (containerViewId != 0) {
            if (containerViewId == View.NO_ID) {
                throw new IllegalArgumentException("Can't add fragment "
                        + fragment + " with tag " + tag + " to container view with no id");
            }
            if (fragment.mFragmentId != 0 && fragment.mFragmentId != containerViewId) {
                throw new IllegalStateException("Can't change container ID of fragment "
                        + fragment + ": was " + fragment.mFragmentId
                        + " now " + containerViewId);
            }
            fragment.mContainerId = fragment.mFragmentId = containerViewId;
        }

        addOp(new Op(opcmd, fragment));
    }
    
    ArrayList<Op> mOps = new ArrayList<>();
    void addOp(Op op) {
        mOps.add(op);
        op.mEnterAnim = mEnterAnim;
        op.mExitAnim = mExitAnim;
        op.mPopEnterAnim = mPopEnterAnim;
        op.mPopExitAnim = mPopExitAnim;
    }
    
    public abstract int commit();
}

校验完合法性后,做了两件事:

  1. 将containerViewId存入到fragment中的mContainerId 和 mFragmentId;

  2. addOp()传入的是一个Op对象,包含标记opcmd和fragment。op对象随后被添加到一个叫mOps的队列中。

看来关键代码在commit身上,所以我们每次用Fragment的时候忘记调用commit就会看不到界面变化。

commit

commit是个抽象方法,其实现在BackStackRecord中:

final class BackStackRecord extends FragmentTransaction implements FragmentManager.BackStackEntry, FragmentManager.OpGenerator {
    @Override
    public int commit() {
        return commitInternal(false);
    }
    
    int commitInternal(boolean allowStateLoss) {
        if (mCommitted) throw new IllegalStateException("commit already called");
        if (FragmentManager.isLoggingEnabled(Log.VERBOSE)) {
            Log.v(TAG, "Commit: " + this);
            LogWriter logw = new LogWriter(TAG);
            PrintWriter pw = new PrintWriter(logw);
            dump("  ", pw);
            pw.close();
        }
        mCommitted = true;
        if (mAddToBackStack) {
            mIndex = mManager.allocBackStackIndex();
        } else {
            mIndex = -1;
        }
        mManager.enqueueAction(this, allowStateLoss);
        return mIndex;
    }
}

mAddToBackStack表示是否加入返回栈,是的话就从manager中返回一个index,表示当前栈中第几个fragment,否则返回-1。

重点方法在enqueueAction中:

enqueueAction

private final ArrayList<OpGenerator> mPendingActions = new ArrayList<>();

void enqueueAction(@NonNull OpGenerator action, boolean allowStateLoss) {
    if (!allowStateLoss) {
        //不允许状态改变
        if (mHost == null) {
            if (mDestroyed) {
                throw new IllegalStateException("FragmentManager has been destroyed");
            } else {
                throw new IllegalStateException("FragmentManager has not been attached to a "
                        + "host.");
            }
        }
        checkStateLoss();//如果已经改变,就在在这个方法内抛错
    }
    synchronized (mPendingActions) {
        if (mHost == null) {
            if (allowStateLoss) {
                // This FragmentManager isn't attached, so drop the entire transaction.
                return;
            }
            throw new IllegalStateException("Activity has been destroyed");
        }
        mPendingActions.add(action);
        scheduleCommit();
    }
}

void scheduleCommit() {
    synchronized (mPendingActions) {
        boolean postponeReady =
            mPostponedTransactions != null && !mPostponedTransactions.isEmpty();
        boolean pendingReady = mPendingActions.size() == 1;
        if (postponeReady || pendingReady) {
            mHost.getHandler().removeCallbacks(mExecCommit);
            mHost.getHandler().post(mExecCommit);
            updateOnBackPressedCallbackEnabled();
        }
    }
}

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

做了三件事:1. 如果不允许状态改变则要做一些检查;

  1. 将action加入mPendingActions队列中;

  2. scheduleCommit

    3.1 (校验判断后)通过Handler将mExecCommit发送出去;

    3.2 处理是否拦截返回事件相关事务【通过返回栈的数目等信息判断】

我们在一开始的时候提到FragmentActivity的onCreate方法中有用到Manager.attachController(),mHost就是传进来的FragmentHostCallback对象。而mHandle是在其构造方法中就已被创建了。

这里用Handle是为了切换到主线程。我们直接关注mExecCommit中的execPendingActions方法就好:

execPendingActions

boolean execPendingActions(boolean allowStateLoss) {
    //准备操作,初始化mTmpRecords,mTmpIsPop等
    ensureExecReady(allowStateLoss);

    boolean didSomething = false;
    while (generateOpsForPendingActions(mTmpRecords, mTmpIsPop)) {
        mExecutingActions = true;
        try {
            removeRedundantOperationsAndExecute(mTmpRecords, mTmpIsPop);
        } finally {
            cleanupExec();
        }
        didSomething = true;
    }

    updateOnBackPressedCallbackEnabled();
    doPendingDeferredStart();
    mFragmentStore.burpActive();

    return didSomething;
}

generateOpsForPendingActions 循环条件

首先看while中的generateOpsForPendingActions:其大致做的事是,遍历完mPendingActions数组,为数组中每个OpGenerator执行generateOps方法。然后清空数组。操作成功返回true,否则【包括数组为null的情况】返回false,

private boolean generateOpsForPendingActions(@NonNull ArrayList<BackStackRecord> records,
        @NonNull 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++) {
            didSomething |= mPendingActions.get(i).generateOps(records, isPop);
        }
        mPendingActions.clear();
        mHost.getHandler().removeCallbacks(mExecCommit);
    }
    return didSomething;
}

而在generateOps方法中,分别向records和isRecordPop中填充元素。

//----------------------BackStackRecord.java下--------------
@Override
public boolean generateOps(@NonNull ArrayList<BackStackRecord> records,
                           @NonNull ArrayList<Boolean> isRecordPop) {
    if (FragmentManager.isLoggingEnabled(Log.VERBOSE)) {
        Log.v(TAG, "Run: " + this);
    }

    records.add(this);
    isRecordPop.add(false);
    if (mAddToBackStack) {
        mManager.addBackStackState(this);
    }
    return true;
}

综上,整个generateOpsForPendingActions的作用就是将mPendingActions中所有的记录<BackStackRecord>添加到了records数组中。

removeRedundantOperationsAndExecute 循环内部

再看循环内部的removeRedundantOperationsAndExecute方法。先猜想一波,刚刚向数组中添加了元素,现在应该操作这些元素了。

//之前的版本中这个方法名叫 optimizeAndExecuteOps
private void removeRedundantOperationsAndExecute(@NonNull ArrayList<BackStackRecord> records,
        @NonNull ArrayList<Boolean> isRecordPop) {
    if (records.isEmpty()) {
        return;
    }

    if (records.size() != isRecordPop.size()) {
        throw new IllegalStateException("Internal error with the back stack records");
    }

    // Force start of any postponed transactions that interact with scheduled transactions:
    //强制启动所有 与计划的transactions交互的 延迟的 transactions。即完成以前已延迟但现在已准备好的事务的transactions
    executePostponedTransaction(records, isRecordPop);

    final int numRecords = records.size();
    int startIndex = 0;
    for (int recordNum = 0; recordNum < numRecords; recordNum++) {
        // 标记是否支持操作排序优化,默认为false
        final boolean canReorder = records.get(recordNum).mReorderingAllowed;
        if (!canReorder) {
            // execute all previous transactions
            if (startIndex != recordNum) {
                executeOpsTogether(records, isRecordPop, startIndex, recordNum);
            }
            // execute all pop operations that don't allow reordering together or
            // one add operation
            int reorderingEnd = recordNum + 1;
            // 非pop事务都返回false
            if (isRecordPop.get(recordNum)) {
                while (reorderingEnd < numRecords
                        && isRecordPop.get(reorderingEnd)
                        && !records.get(reorderingEnd).mReorderingAllowed) {
                    reorderingEnd++;
                }
            }
            executeOpsTogether(records, isRecordPop, recordNum, reorderingEnd);
            startIndex = reorderingEnd;
            recordNum = reorderingEnd - 1;
        }
    }
    if (startIndex != numRecords) {
        // 开启操作排序优化情况下可能会满足该if条件
        executeOpsTogether(records, isRecordPop, startIndex, numRecords);
    }
}

之前的版本中这个方法名叫 optimizeAndExecuteOps【优化并执行】,现在叫removeRedundantOperationsAndExecute【删除冗余操作并执行】。从命名可以看出Google开发团队对这个方法做出的解释--当有多个待执行事务时,FragmentManager会删除部分冗余事务操作。例如:

  • 假设有两个事务对同一布局容器一起执行,一个事务添加了一个 Fragment A,下一个事务将其替换为 Fragment B。则优化后会将第一个操作取消,仅添加 Fragment B。
  • 假设有三个事务,一个事务添加了 Fragment A,第二个事务添加了 Fragment B,然后第三个删除了 Fragment A。那么优化后将不会执行 Fragment A的添加和删除,仅添加 Fragment B。

排序优化操作会导致出现超出开发者预期的行为,因此默认不进行此操作。

参考博客:https://juejin.cn/post/6844904090485391368

实际实现的代码时executeOpsTogether()方法。

private void executeOpsTogether(@NonNull ArrayList<BackStackRecord> records,
        @NonNull ArrayList<Boolean> isRecordPop, int startIndex, int endIndex) {
    final boolean allowReordering = records.get(startIndex).mReorderingAllowed;
    boolean addToBackStack = false;
    if (mTmpAddedFragments == null) {
        mTmpAddedFragments = new ArrayList<>();
    } else {
        mTmpAddedFragments.clear();
    }
    mTmpAddedFragments.addAll(mFragmentStore.getFragments());
    Fragment oldPrimaryNav = getPrimaryNavigationFragment();
    for (int recordNum = startIndex; recordNum < endIndex; recordNum++) {
        final BackStackRecord record = records.get(recordNum);
        final boolean isPop = isRecordPop.get(recordNum);
        if (!isPop) {
            oldPrimaryNav = record.expandOps(mTmpAddedFragments, oldPrimaryNav);
        } else {
            oldPrimaryNav = record.trackAddedFragmentsInPop(mTmpAddedFragments, oldPrimaryNav);
        }
        addToBackStack = addToBackStack || record.mAddToBackStack;
    }
    mTmpAddedFragments.clear();

    if (!allowReordering) {
        FragmentTransition.startTransitions(this, records, isRecordPop, startIndex, endIndex,
                false, mFragmentTransitionCallback);
    }
    executeOps(records, isRecordPop, startIndex, endIndex);

    int postponeIndex = endIndex;
    if (allowReordering) {
        ArraySet<Fragment> addedFragments = new ArraySet<>();
        addAddedFragments(addedFragments);
        postponeIndex = postponePostponableTransactions(records, isRecordPop,
                startIndex, endIndex, addedFragments);
        makeRemovedFragmentsInvisible(addedFragments);
    }

    if (postponeIndex != startIndex && allowReordering) {
        // need to run something now
        FragmentTransition.startTransitions(this, records, isRecordPop, startIndex,
                postponeIndex, true, mFragmentTransitionCallback);
        moveToState(mCurState, true);
    }

    for (int recordNum = startIndex; recordNum < endIndex; recordNum++) {
        final BackStackRecord record = records.get(recordNum);
        final boolean isPop = isRecordPop.get(recordNum);
        if (isPop && record.mIndex >= 0) {
            record.mIndex = -1;
        }
        record.runOnCommitRunnables();
    }
    if (addToBackStack) {
        reportBackStackChanged();
    }
}
executeOps(records, isRecordPop, startIndex, endIndex);
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);
            // Only execute the add operations at the end of
            // all transactions.
            boolean moveToState = i == (endIndex - 1);
            record.executePopOps(moveToState);
        } else {
            record.bumpBackStackNesting(1);
            record.executeOps();
        }
    }
}

record.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.mFragment;
        if (f != null) {
            f.setNextTransition(mTransition);
        }
        switch (op.mCmd) {
            case OP_ADD:
                f.setNextAnim(op.mEnterAnim);
                mManager.setExitAnimationOrder(f, false);
                mManager.addFragment(f);
                break;
            case OP_REMOVE:
                f.setNextAnim(op.mExitAnim);
                mManager.removeFragment(f);
                break;
            case OP_HIDE:
                f.setNextAnim(op.mExitAnim);
                mManager.hideFragment(f);
                break;
            case OP_SHOW:
                f.setNextAnim(op.mEnterAnim);
                mManager.setExitAnimationOrder(f, false);
                mManager.showFragment(f);
                break;
            case OP_DETACH:
                f.setNextAnim(op.mExitAnim);
                mManager.detachFragment(f);
                break;
            case OP_ATTACH:
                f.setNextAnim(op.mEnterAnim);
                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) {
            mManager.moveFragmentToExpectedState(f);
        }
    }
    if (!mReorderingAllowed) {
        // Added fragments are added at the end to comply with prior behavior.
        mManager.moveToState(mManager.mCurState, true);
    }
}

在这里根据不同的命令,执行不同的操作。最后MoveToState。

MoveToState(int,boolean)

void moveToState(int newState, boolean always) {
    if (mHost == null && newState != Fragment.INITIALIZING) {
        throw new IllegalStateException("No activity");
    }

    if (!always && newState == mCurState) {
        return;
    }

    mCurState = newState;

    // Must add them in the proper order. mActive fragments may be out of order
    for (Fragment f : mFragmentStore.getFragments()) {
        moveFragmentToExpectedState(f);
    }

    // Now iterate through all active fragments. These will include those that are removed
    // and detached.
    for (Fragment f : mFragmentStore.getActiveFragments()) {
        if (f != null && !f.mIsNewlyAdded) {
            moveFragmentToExpectedState(f);
        }
    }

    startPendingDeferredFragments();

    if (mNeedMenuInvalidate && mHost != null && mCurState == Fragment.RESUMED) {
        mHost.onSupportInvalidateOptionsMenu();
        mNeedMenuInvalidate = false;
    }
}

最终把Fragment展示出来实现的方法是moveFragemtnTOExpectedState(f);

void moveFragmentToExpectedState(@NonNull Fragment f) {
    if (!mFragmentStore.containsActiveFragment(f.mWho)) {
        if (isLoggingEnabled(Log.DEBUG)) {
            Log.d(TAG, "Ignoring moving " + f + " to state " + mCurState
                    + "since it is not added to " + this);
        }
        return;
    }
    moveToState(f);

    if (f.mView != null) {
        // Move the view if it is out of order
        Fragment underFragment = mFragmentStore.findFragmentUnder(f);
        if (underFragment != null) {
            final View underView = underFragment.mView;
            // make sure this fragment is in the right order.
            final ViewGroup container = f.mContainer;
            int underIndex = container.indexOfChild(underView);
            int viewIndex = container.indexOfChild(f.mView);
            if (viewIndex < underIndex) {
                container.removeViewAt(viewIndex);
                container.addView(f.mView, underIndex);
            }
        }
        if (f.mIsNewlyAdded && f.mContainer != null) {
            // Make it visible and run the animations
            if (f.mPostponedAlpha > 0f) {
                f.mView.setAlpha(f.mPostponedAlpha);
            }
            f.mPostponedAlpha = 0f;
            f.mIsNewlyAdded = false;
            // run animations:
            FragmentAnim.AnimationOrAnimator anim = FragmentAnim.loadAnimation(
                    mHost.getContext(), mContainer, f, true);
            if (anim != null) {
                if (anim.animation != null) {
                    f.mView.startAnimation(anim.animation);
                } else {
                    anim.animator.setTarget(f.mView);
                    anim.animator.start();
                }
            }
        }
    }
    if (f.mHiddenChanged) {
        completeShowHideFragment(f);
    }
}

void moveToState(@NonNull Fragment f) {
    moveToState(f, mCurState);
}

跟着这个moveToState(Fragment,int)才是主角:在生命周期的每个阶段要做什么,都写的很清楚。

void moveToState(@NonNull Fragment f, int newState) {
    FragmentStateManager fragmentStateManager = mFragmentStore.getFragmentStateManager(f.mWho);
    if (fragmentStateManager == null) {
        // Ideally, we only call moveToState() on active Fragments. However,
        // in restoreSaveState() we can call moveToState() on retained Fragments
        // just to clean them up without them ever being added to mActive.
        // For these cases, a brand new FragmentStateManager is enough.
        fragmentStateManager = new FragmentStateManager(mLifecycleCallbacksDispatcher, f);
        // Only allow this FragmentStateManager to go up to CREATED at the most
        fragmentStateManager.setFragmentManagerState(Fragment.CREATED);
    }
    newState = Math.min(newState, fragmentStateManager.computeMaxState());
    if (f.mState <= newState) {
        // If we are moving to the same state, we do not need to give up on the animation.
        if (f.mState < newState && !mExitAnimationCancellationSignals.isEmpty()) {
            // The fragment is currently being animated...  but!  Now we
            // want to move our state back up.  Give up on waiting for the
            // animation and proceed from where we are.
            cancelExitAnimation(f);
        }
        switch (f.mState) {
            case Fragment.INITIALIZING:
                if (newState > Fragment.INITIALIZING) {
                    if (isLoggingEnabled(Log.DEBUG)) Log.d(TAG, "moveto ATTACHED: " + f);

                    // 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 (!f.mTarget.equals(findActiveFragment(f.mTarget.mWho))) {
                            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);
                        }
                        f.mTargetWho = f.mTarget.mWho;
                        f.mTarget = null;
                    }
                    if (f.mTargetWho != null) {
                        Fragment target = findActiveFragment(f.mTargetWho);
                        if (target == null) {
                            throw new IllegalStateException("Fragment " + f
                                    + " declared target fragment " + f.mTargetWho
                                    + " that does not belong to this FragmentManager!");
                        }
                        if (target.mState < Fragment.CREATED) {
                            moveToState(target, Fragment.CREATED);
                        }
                    }

                    fragmentStateManager.attach(mHost, this, mParent);
                }
                // fall through
            case Fragment.ATTACHED:
                if (newState > Fragment.ATTACHED) {
                    fragmentStateManager.create();
                }
                // fall through
            case Fragment.CREATED:
                // We want to unconditionally run this anytime we do a moveToState that
                // moves the Fragment above INITIALIZING, including cases such as when
                // we move from CREATED => CREATED as part of the case fall through above.
                if (newState > Fragment.INITIALIZING) {
                    fragmentStateManager.ensureInflatedView();
                }

                if (newState > Fragment.CREATED) {
                    fragmentStateManager.createView(mContainer);
                    fragmentStateManager.activityCreated();
                    fragmentStateManager.restoreViewState();
                }
                // fall through
            case Fragment.ACTIVITY_CREATED:
                if (newState > Fragment.ACTIVITY_CREATED) {
                    fragmentStateManager.start();
                }
                // fall through
            case Fragment.STARTED:
                if (newState > Fragment.STARTED) {
                    fragmentStateManager.resume();
                }
        }
    } else if (f.mState > newState) {
        ....
    }

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

所以就会按顺序执行FragmentStateManager的attach--create---createView--activityCreated--start--resume方法。

以FragmentManager中的attach方法和create方法为例:

FragementManager-attach/create

void attach(@NonNull FragmentHostCallback<?> host, @NonNull FragmentManager fragmentManager,
        @Nullable Fragment parentFragment) {
    mFragment.mHost = host;
    mFragment.mParentFragment = parentFragment;
    mFragment.mFragmentManager = fragmentManager;
    mDispatcher.dispatchOnFragmentPreAttached(
            mFragment, host.getContext(), false);
    mFragment.performAttach();
    if (mFragment.mParentFragment == null) {
        host.onAttachFragment(mFragment);
    } else {
        mFragment.mParentFragment.onAttachFragment(mFragment);
    }
    mDispatcher.dispatchOnFragmentAttached(
            mFragment, host.getContext(), false);
}

void create() {
    if (FragmentManager.isLoggingEnabled(Log.DEBUG)) {
        Log.d(TAG, "moveto CREATED: " + mFragment);
    }
    if (!mFragment.mIsCreated) {
        mDispatcher.dispatchOnFragmentPreCreated(
                mFragment, mFragment.mSavedFragmentState, false);
        mFragment.performCreate(mFragment.mSavedFragmentState);
        mDispatcher.dispatchOnFragmentCreated(
                mFragment, mFragment.mSavedFragmentState, false);
    } else {
        mFragment.restoreChildFragmentState(mFragment.mSavedFragmentState);
        mFragment.mState = Fragment.CREATED;
    }
}

最后会调用到performAttach/performCreate方法:

void performAttach() {
    mChildFragmentManager.attachController(mHost, new FragmentContainer() {
        @Override
        @Nullable
        public View onFindViewById(int id) {
            if (mView == null) {
                throw new IllegalStateException("Fragment " + this + " does not have a view");
            }
            return mView.findViewById(id);
        }

        @Override
        public boolean onHasView() {
            return (mView != null);
        }
    }, this);
    mState = ATTACHED;
    mCalled = false;
    onAttach(mHost.getContext());
    if (!mCalled) {
        throw new SuperNotCalledException("Fragment " + this
                + " did not call through to super.onAttach()");
    }
}

void performCreate(Bundle savedInstanceState) {
    mChildFragmentManager.noteStateNotSaved();
    mState = CREATED;
    mCalled = false;
    mSavedStateRegistryController.performRestore(savedInstanceState);
    onCreate(savedInstanceState);
    mIsCreated = true;
    if (!mCalled) {
        throw new SuperNotCalledException("Fragment " + this
                + " did not call through to super.onCreate()");
    }
    mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
}

最后终于调用到了我们自己重写的的onAttach/onCreate方法里面。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,723评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,485评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,998评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,323评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,355评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,079评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,389评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,019评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,519评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,971评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,100评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,738评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,293评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,289评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,517评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,547评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,834评论 2 345

推荐阅读更多精彩内容