Fragment的创建分析

news2024/11/25 4:39:51

        之前的文章讨论了Fragment的销毁流程,初始状态为resume,然后经历pause -> stop -> destroyView -> destroy -> detach这么几个流程(本篇文章基于Support27.1.1来分析的)。清楚了Fragment的销毁,那也来看看Fragment的创建,这里先放一张Fragment生命周期的图,如下:

        该图包含了Fragment从创建到销毁的所有生命周期方法及与相应Activity生命周期状态的对关系,相应面试过程中如果遇到Fragment相关的问题,应该都不会逃过生命周期相关的问题。然而生命周期只是Fragment运行的表现,它是如何一步步运行起来的呢?这篇文章聚焦Fragment的创建,从源码角度分析Fragment的创建流程。

        由于Fragment的流程依附于相应Activity的生命周期,因此这里以Activity的onCreate、onStart、onResume为主线来说明Fragment的生命周期是如何转换的。

目录

1. Activity.onCreate

2. Activity.onStart

3. Activity.onResume


1. Activity.onCreate

        在Activity的onCreate执行的时候,我们的Fragment则经历了onAttach -> onCreate ->onCreateView -> onActivityCreated几个生命周期方法,下面从FragmentActivity的onCreate开始分析,老规矩上代码:

@SuppressWarnings("deprecation")
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        mFragments.attachHost(null /*parent*/);//A

        super.onCreate(savedInstanceState);

        NonConfigurationInstances nc =
                (NonConfigurationInstances) getLastNonConfigurationInstance();
        if (nc != null) {
            mViewModelStore = nc.viewModelStore;
        }
        if (savedInstanceState != null) {//B
            Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);
            mFragments.restoreAllState(p, nc != null ? nc.fragments : null);

            // Check if there are any pending onActivityResult calls to descendent Fragments.
            if (savedInstanceState.containsKey(NEXT_CANDIDATE_REQUEST_INDEX_TAG)) {
                mNextCandidateRequestIndex =
                        savedInstanceState.getInt(NEXT_CANDIDATE_REQUEST_INDEX_TAG);
                int[] requestCodes = savedInstanceState.getIntArray(ALLOCATED_REQUEST_INDICIES_TAG);
                String[] fragmentWhos = savedInstanceState.getStringArray(REQUEST_FRAGMENT_WHO_TAG);
                if (requestCodes == null || fragmentWhos == null ||
                            requestCodes.length != fragmentWhos.length) {
                    Log.w(TAG, "Invalid requestCode mapping in savedInstanceState.");
                } else {
                    mPendingFragmentActivityResults = new SparseArrayCompat<>(requestCodes.length);
                    for (int i = 0; i < requestCodes.length; i++) {
                        mPendingFragmentActivityResults.put(requestCodes[i], fragmentWhos[i]);
                    }
                }
            }
        }

        if (mPendingFragmentActivityResults == null) {
            mPendingFragmentActivityResults = new SparseArrayCompat<>();
            mNextCandidateRequestIndex = 0;
        }

        mFragments.dispatchCreate();//C
    }

        上面的代码中用注释标识了A/B/C三处代码,A处相当于是Fragment运行环境的初始化,B处是状态的恢复,C处是Fragment生命周期的状态转换;我们重点看A/C两处,先看A,代码如下:

    
//FragmentActivity.java
final FragmentController mFragments = FragmentController.createController(new HostCallbacks());

    //FragmentController.java
    /**
     * Attaches the host to the FragmentManager for this controller. The host must be
     * attached before the FragmentManager can be used to manage Fragments.
     */
    public void attachHost(Fragment parent) {
        mHost.mFragmentManager.attachController(
                mHost, mHost /*container*/, parent);
    }

    //FragmentManager.java
    public void attachController(FragmentHostCallback host,
            FragmentContainer container, Fragment parent) {
        if (mHost != null) throw new IllegalStateException("Already attached");
        mHost = host;
        mContainer = container;
        mParent = parent;
    }

         调用attachHost把相关参数传递到FragmentManager中,mHost、mContainer的值都为在FragmentActivity中创建的HostCallbacks对象,mParent则为空,Activity中的第一个Fragment的mParentFragment对象总是空的,因为它就是第一个Fragment。

        mFragments.dispatchCreate()这行代码开启了Fragment生命周期的轮转,经过前面的分析我们知道最终会到FragmentManager中5个参数版本的moveToState方法中,这里简单贴下中间跳转代码:

    /**
     * Moves all Fragments managed by the controller's FragmentManager
     * into the create state.
     * <p>Call when Fragments should be created.
     *
     * @see Fragment#onCreate(Bundle)
     */
    public void dispatchCreate() {
        mHost.mFragmentManager.dispatchCreate();
    }

    public void dispatchCreate() {
        mStateSaved = false;
        mStopped = false;
        dispatchStateChange(Fragment.CREATED);//注意该值
    }

    private void dispatchStateChange(int nextState) {
        try {
            mExecutingActions = true;
            moveToState(nextState, false);
        } finally {
            mExecutingActions = false;
        }
        execPendingActions();
    }

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

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

        mCurState = newState;

        if (mActive != null) {

            // Must add them in the proper order. mActive fragments may be out of order
            final int numAdded = mAdded.size();
            for (int i = 0; i < numAdded; i++) {
                Fragment f = mAdded.get(i);
                moveFragmentToExpectedState(f);
            }

            // Now iterate through all active fragments. These will include those that are removed
            // and detached.
            final int numActive = mActive.size();
            for (int i = 0; i < numActive; i++) {
                Fragment f = mActive.valueAt(i);
                if (f != null && (f.mRemoving || f.mDetached) && !f.mIsNewlyAdded) {
                    moveFragmentToExpectedState(f);
                }
            }

            startPendingDeferredFragments();

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

    void moveFragmentToExpectedState(Fragment f) {
        if (f == null) {
            return;
        }
        int nextState = mCurState;
        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);//状态转换入口

        if (f.mView != null) {
            // Move the view if it is out of order
            Fragment underFragment = 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:
                AnimationOrAnimator anim = loadAnimation(f, f.getNextTransition(), true,
                        f.getNextTransitionStyle());
                if (anim != null) {
                    setHWLayerAnimListenerIfAlpha(f.mView, anim);
                    if (anim.animation != null) {
                        f.mView.startAnimation(anim.animation);
                    } else {
                        anim.animator.setTarget(f.mView);
                        anim.animator.start();
                    }
                }
            }
        }
        if (f.mHiddenChanged) {
            completeShowHideFragment(f);
        }
    }


        嗯,一堆堆代码了,moveToState(f, nextState, f.getNextTransition(), f.getNextTransitionStyle(), false); 最后这行代码正式进入生命周期转换当中,通过前面的分析知道分为创建和销毁两大流程,这里省略销毁流程,创建流程代码如下:

    @SuppressWarnings("ReferenceEquality")
    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.STOPPED) {
            newState = Fragment.STOPPED;
        }
        if (f.mState <= newState) {
            //这里是创建流程 attach -> create -> creatView -> activityCreated ->
            // start -> resume
            // 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.STOPPED) {
                                    newState = Fragment.STOPPED;
                                }
                            }
                        }

                        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.mView = 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) {
                        f.mState = Fragment.STOPPED;
                    }
                    // fall through
                case Fragment.STOPPED:
                    if (newState > Fragment.STOPPED) {
                        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) {
            //这里是销毁流程 pause -> stop -> destoroyView -> destory -> detach
        }

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

        首次进入Fragment的状态为Fragment.INITIALIZING,而前面调用dispatchCreate 时传递的状态nextState参数为Fragment.CREATED,因此newState为Fragment.CREATED,所以上面的创建流程会进入到Fragment.INITIALIZING对应的分支,这里单独拿出该分支代码如下:

    if (newState > Fragment.INITIALIZING) {
        if (DEBUG) Log.v(TAG, "moveto CREATED: " + f);
        if (f.mSavedFragmentState != null) {//A
            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.STOPPED) {
                    newState = Fragment.STOPPED;
                }
            }
        }
        //B
        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);
            }
        }
        //C
        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) {//D
            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;
    }

        上面的代码标注了A/B/C/D四处,A处主要是状态恢复,B处mHost、mParentFragment、mFragmentManager的赋值,C处调用了生命周期方法onAttach,D处则调用了onCreate,这里关注C/D两处,先看C处代码如下:

    /**
     * Called when a fragment is first attached to its context.
     * {@link #onCreate(Bundle)} will be called after this.
     */
    @CallSuper
    public void onAttach(Context context) {
        mCalled = true;
        final Activity hostActivity = mHost == null ? null : mHost.getActivity();
        if (hostActivity != null) {
            mCalled = false;
            onAttach(hostActivity);
        }
    }

        简单的调用了 onAttach而已。

tips:这里的onAttach方法有两个版本,一个是带Context参数的,一个是带Activity参数的,其实通过代码分析发现传递过来的始终是Activity对象。

        再看D处,代码如下:

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

    @CallSuper
    public void onCreate(@Nullable Bundle savedInstanceState) {
        mCalled = true;
        restoreChildFragmentState(savedInstanceState);
        if (mChildFragmentManager != null
                && !mChildFragmentManager.isStateAtLeast(Fragment.CREATED)) {
            mChildFragmentManager.dispatchCreate();
        }
    }

         也是简单回调,同时重置mIsCreated为true(避免重复调用吧),注意这里也会调用恢复子Fragment的状态。

onCreate调用完毕,Fragment的mState为CREATED,相应FragmentManager内部的mCurState为CREATED。

         Fragment的onCreate调用完毕,继续运行;switch代码穿透到Fragment.CREATED分支,这里根据Fragment和相应FragmentManager的状态对比,并不会进入该分支的if语句内部(表明当前执行到了Fragment.CREATED这个状态)。但是以下代码会执行:

void ensureInflatedFragmentView(Fragment f) {
        if (f.mFromLayout && !f.mPerformedCreateView) {
            f.mView = f.performCreateView(f.performGetLayoutInflater(
                    f.mSavedFragmentState), null, f.mSavedFragmentState);
            if (f.mView != null) {
                f.mInnerView = f.mView;
                f.mView.setSaveFromParentEnabled(false);
                if (f.mHidden) f.mView.setVisibility(View.GONE);
                f.onViewCreated(f.mView, f.mSavedFragmentState);
                dispatchOnFragmentViewCreated(f, f.mView, f.mSavedFragmentState, false);
            } else {
                f.mInnerView = null;
            }
        }
    }

        如果Fragment是在布局中加载的,这里就会创建Fragment的View了,这里假设不是,我们继续分析。

        Activity.onCreate执行完毕,发现只调用了相应Fragment的onAttach和onCreate方法,貌似与开篇上的图有差别(知道就行了,别怪我的图,我也是不知道从哪里拿来的)。 

2. Activity.onStart

        现在进入Activity的onStart方法,代码如下:

    @Override
    protected void onStart() {
        super.onStart();

        mStopped = false;
        mReallyStopped = false;
        mHandler.removeMessages(MSG_REALLY_STOPPED);

        if (!mCreated) {
            mCreated = true;
            mFragments.dispatchActivityCreated();//A
        }

        mFragments.noteStateNotSaved();
        mFragments.execPendingActions();

        // NOTE: HC onStart goes here.

        mFragments.dispatchStart();//B
    }

        关注A/B两处,这里的状态分发都会进入到FragmentManager里面5个参数的moveToState方法中,所以中间的过程省略了。

        先看A处,还是关注传递的参数,代码如下:

public void dispatchActivityCreated() {
        mStateSaved = false;
        mStopped = false;
        dispatchStateChange(Fragment.ACTIVITY_CREATED);
    }

         这里传递了Fragment.ACTIVITY_CREATED,因此FragmengManager中mCurState会变为Fragment.ACTIVITY_CREATED,但是相应Fragment的状态mState还是CREATED(即将要变为ACTIVITY_CREATED),所以进入到moveToState的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) {//A
                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 (Resources.NotFoundException e) {
                        resName = "unknown";
                    }
                    throwException(new IllegalArgumentException(
                            "No view found for id 0x"
                                    + Integer.toHexString(f.mContainerId) + " ("
                                    + resName
                                    + ") for fragment " + f));
                }
            }
            //B
            f.mContainer = container;
            f.mView = 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);
                }
                //C
                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;
            }
        }

        //D
        f.performActivityCreated(f.mSavedFragmentState);
        dispatchOnFragmentActivityCreated(f, f.mSavedFragmentState, false);
        if (f.mView != null) {
            f.restoreViewState(f.mSavedFragmentState);
        }
        f.mSavedFragmentState = null;
    }

        ensureInflatedFragmentView已经分析过,不再说明; 上面的代码标记了A/B/C/D四处,这里会一一说明,A处主要是找到相应activity中Fragment的容器View,如果找不到则会抛异常。

我们通过如下代码动态添加Fragment

FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
        ft.add(R.id.container, new FragmentLifeTest(), "FragmentLifeTest")
                .commitAllowingStateLoss();

上面分析的A处其实就是找到R.id.containe对应的View(该View是相应Fragment的View的容器)

         B处把A处找到的容器保存到Fragment的mContainer成员变量中,接着调用方法performCreateView,该方法会返回Fragment对应的View视图,接着把返回的View视图添加到mContainer中(嗯,Fragment的视图还是通过操作activity中的容器添加到activity视图中的),来看下performCreateView方法,代码如下:

    View performCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
            @Nullable Bundle savedInstanceState) {
        if (mChildFragmentManager != null) {
            mChildFragmentManager.noteStateNotSaved();
        }
        mPerformedCreateView = true;
        return onCreateView(inflater, container, savedInstanceState);
    }

        比较简单,调用onCreateView返回Fragment对应的View,没啥说的。 

        接着分析,来到C处,调用onViewCreated,嗯,这里直接调用了Fragment的onViewCreated方法,传递了刚刚返回的Fragment对应的View,说明此时View已经创建;所以我们再写Fragment的时候通常会把UI的初始化逻辑写在onViewCreated中,这回知道原因了吧。

        最后是D处,performActivityCreated,代码如下:

    void performActivityCreated(Bundle savedInstanceState) {
        if (mChildFragmentManager != null) {
            mChildFragmentManager.noteStateNotSaved();
        }
        mState = ACTIVITY_CREATED;
        mCalled = false;
        onActivityCreated(savedInstanceState);
        if (!mCalled) {
            throw new SuperNotCalledException("Fragment " + this
                    + " did not call through to super.onActivityCreated()");
        }
        if (mChildFragmentManager != null) {
            mChildFragmentManager.dispatchActivityCreated();
        }
    }

        也是简单的调用了onActivityCreated,注意这里Fragment状态发生了改变,变为ACTIVITY_CREATED。

执行完Activity.onStart方法之后,Fragment的状态从CREATED转变为了ACTIVITY_CREATED。

        继续分析 ,CREATED分支执行完毕,代码继续运行,进入ACTIVITY_CREATED分支,经过分析,该分支条件不满足,最后退出整个switch代码块。

分析完Activity.onStart的第一部分dispatchActivityCreated,我们知道对应的Fragment主要执行了onCreateView -> onViewCreated -> onActivityCreated

        进入 Activity.onStart的第二部分dispatchStart,相关传参代码如下:

    public void dispatchStart() {
        mStateSaved = false;
        mStopped = false;
        dispatchStateChange(Fragment.STARTED);
    }

        参数为 Fragment.STARTE,则FragmentManager的mCurState会变为Fragment.STARTE,而Fragment此时还是上一个状态即:ACTIVITY_CREATED,因此执行如下代码:

    case Fragment.ACTIVITY_CREATED:
        if (newState > Fragment.ACTIVITY_CREATED) {
            f.mState = Fragment.STOPPED;
        }

        太简单了,一个瞬时状态,Fragment的状态直接变为Fragment.STOPPED了,继续分析,由于传递的nextState为Fragment.STARTE,因此进入如下代码:

    case Fragment.STOPPED:
        if (newState > Fragment.STOPPED) {
            if (DEBUG) Log.v(TAG, "moveto STARTED: " + f);
            f.performStart();
            dispatchOnFragmentStarted(f, false);
        }
        // fall through

        调用了Fragment的performStart方法,该方法代码如下:

    void performStart() {
        if (mChildFragmentManager != null) {
            mChildFragmentManager.noteStateNotSaved();
            mChildFragmentManager.execPendingActions();
        }
        mState = STARTED;
        mCalled = false;
        onStart();
        if (!mCalled) {
            throw new SuperNotCalledException("Fragment " + this
                    + " did not call through to super.onStart()");
        }
        if (mChildFragmentManager != null) {
            mChildFragmentManager.dispatchStart();
        }
        mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START);
    }

         Fragment的状态变为了STARTED,同时调用Fragment的生命周期方法onStart。

        代码继续运行,进入到Fragment.STARTED分支,但是此时条件不满足,因此退出switch代码块。

总结起来,在activity的onSart生命周期中,相应Fragment调用了经历了:onCreateView -> onViewCreated -> onActivityCreated -> onStart。相应状态mState最终变为了Fragment.STARTED。

3. Activity.onResume

        到了Activity的onResume阶段,Fragment的创建也快完成了,Activity入口处代码如下:

    /**
     * Dispatch onResume() to fragments.  Note that for better inter-operation
     * with older versions of the platform, at the point of this call the
     * fragments attached to the activity are <em>not</em> resumed.  This means
     * that in some cases the previous state may still be saved, not allowing
     * fragment transactions that modify the state.  To correctly interact
     * with fragments in their proper state, you should instead override
     * {@link #onResumeFragments()}.
     */
    @Override
    protected void onResume() {
        super.onResume();
        mHandler.sendEmptyMessage(MSG_RESUME_PENDING);
        mResumed = true;
        mFragments.execPendingActions();
    }

        发送了一个消息去执行Fragment的resume(为啥这里要这样做呢?不太理解,希望有明白的读者不吝指教),MSG_RESUME_PENDING对应的代码如下:

    final Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_REALLY_STOPPED:
                    if (mStopped) {
                        doReallyStop(false);
                    }
                    break;
                case MSG_RESUME_PENDING:
                    onResumeFragments();
                    mFragments.execPendingActions();
                    break;
                default:
                    super.handleMessage(msg);
            }
        }

    };

    /**
     * This is the fragment-orientated version of {@link #onResume()} that you
     * can override to perform operations in the Activity at the same point
     * where its fragments are resumed.  Be sure to always call through to
     * the super-class.
     */
    protected void onResumeFragments() {
        mFragments.dispatchResume();
    }

        还是调用mFragments.dispatchResume把Activity相关的事件传递到FragmentManager中进行分发,贴出部分传参的关键代码:

    public void dispatchResume() {
        mStateSaved = false;
        mStopped = false;
        dispatchStateChange(Fragment.RESUMED);
    }

        这里传递了Fragment.RESUMED,则相应FragmentManager中的mCurState为Fragment.RESUMED,而Fragment还是上一个状态Fragment.STARTED,因此在moveToState方法中会执行如下代码:

    // 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;
        }

        调用perormResume,同时调用dispatchOnFragmentResumed分发resume事件,这里看看perormResume,代码如下:

    void performResume() {
        if (mChildFragmentManager != null) {
            mChildFragmentManager.noteStateNotSaved();
            mChildFragmentManager.execPendingActions();
        }
        mState = RESUMED;
        mCalled = false;
        onResume();
        if (!mCalled) {
            throw new SuperNotCalledException("Fragment " + this
                    + " did not call through to super.onResume()");
        }
        if (mChildFragmentManager != null) {
            mChildFragmentManager.dispatchResume();
            mChildFragmentManager.execPendingActions();
        }
        mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME);
    }

        修改Fragment的状态为Fragment.RESUMED,调用onResume生命周期方法,调用通过LifecycleRegistry注册的resume事件。

执行完Activity.onResume,相应的Fragment状态也变为了Fragment.RESUMED。

        到此,Fragment的创建算是完成了,从源码角度分析了activity中的生命周期对应的Fragment生命周期事件;若是你能读到这里,相信会有所收获。 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/979104.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

《向量数据库指南》——AI原生向量数据库Milvus Cloud 2.3架构升级

架构升级 GPU 支持 早在 Milvus 1.x 版本,我们就曾经支持过 GPU,但在 2.x 版本中由于切换成了分布式架构,同时出于对于成本方面的考虑,暂时未加入 GPU 支持。在 Milvus 2.0 发布后的一年多时间里,Milvus 社区对 GPU 的呼声越来越高,再加上 NVIDIA 工程师的大力配合——为…

CTFHUB ICS(1)

1.异常的工程文件 把文件拖到kali里面去了 unzip 文件名解压文件 文件很多&#xff0c;我们先进到解压的文件夹里面 strings $(find . | xargs) | grep flag linux命令的作用是在当前目录及子目录下递归查找文件,提取文件中的字符串,然后用grep过滤 find . - 在当前目录及递…

cadence virtuoso bandgap温漂公式

先仿真温漂&#xff0c;然后将曲线send to calculate。 调用ymax&#xff0c;ymin&#xff0c;average函数。

PGInfo核心字段详解

PGInfo存在于PG的整个生命周期中&#xff0c;其在对象数据的写入、数据恢复、PG Peering过程中均发挥重要的作用。本章试图研究pg info在整个PG生命周期中的变化过程&#xff0c;从而对PG及PGInfo有一个更深入的理解。 class PG : DoutPrefixProvider { public:// pg statepg_…

Unable to remove Temporary User Data

错误截图 原因 项目的临时数据目录是存在了未授权的盘符&#xff0c;当删除它的时候&#xff0c;遇到了权限问题&#xff0c;没有权限没法删除。 解决方法 增加字段&#xff1a;userDataDir 解决

WSL使用技巧 / 虚拟机对比

WSL使用技巧 / 虚拟机对比 前言虚拟机比较VMware使用技巧WSL使用技巧官方文档工具安装WSL基本命令运行命令关闭卸载磁盘管理导入导出指定安装路径 前言 本文介绍了VMware和WSL的区别&#xff0c;并详细介绍了WSL的使用方法和技巧。 虚拟机比较 VMware 比较灵活&#xff0c;拥…

高压放大器该如何选择(高压放大器选型要求有哪些)

选择适合的高压放大器对于电子设备和实验中的特定应用非常重要。高压放大器通常用于放大高电压信号&#xff0c;如激光驱动、粒子加速器、电力系统和医学成像等领域。在选择高压放大器时&#xff0c;以下几个因素值得考虑。 首先&#xff0c;您需要确定所需的输出电压范围。不同…

Date.toLocaleString()不同系统语言之会返回不同的format(可能导致我查的出来数据别人查不出来)

最近发生了个Bug,访问部署在服务器上的服务&#xff0c;我选了时间之后查的出来数据&#xff0c;别人就不行&#xff0c;同样的条件&#xff0c;同样的时区。百思不得解。 直到看了 request里面的参数&#xff0c;发现怎么format不一致&#xff0c;都是访问的服务器部署的服务。…

Linux下的系统编程——进程的执行与回收(八)

前言&#xff1a; 前面我们对进程已经有了一个初步的了解与认识&#xff0c;现在让我们学习一下进程中一些函数的具体使用&#xff0c;比如exec可以执行一些指定的程序&#xff0c;wait / waitpid可以回收子进程&#xff0c;什么是孤儿进程&#xff0c;什么是僵尸进程&#xf…

性能测试实现天罗地网对各个中间件实现监控

名师出高徒&#xff0c;我亲自带你出征&#xff0c;直捣黄龙。高手都是顶峰相见&#xff01;将军有剑 不斩苍蝇&#xff0c;将军赶路&#xff0c;不追小兔。赶紧上车 带你入行就是高手。

【ccf-csp题解】第1次csp认证-第三题-命令行选项-题解

题目描述 思路讲解 本题是一个简单的字符串模拟题&#xff0c;这种题目是csp认证第三题的常客 大致思路是用两个bool数组记录某一个选项&#xff08;0--25下标对应小写字母a--z&#xff09;&#xff0c;第一个数组中无参选项为true&#xff0c;第二个数组中有参选项为true&a…

【算法系列篇】分治-归并

文章目录 前言什么是归并算法1. 排序数组1.1 题目要求1.2 做题思路1.3 Java代码实现 2. 数组中逆序对2.1 题目要求2.2 做题思路2.3 Java代码实现 3. 计算右侧小于当前元素的个数3.1 题目要求3.2 做题思路3.3 Java代码实现 4. 翻转对4.1 题目要求4.2 做题思路4.3 Java代码实现 总…

金融信创,软件规划需关注自主安全及生态建设

软件信创化&#xff0c;就是信息技术软件应用创新发展的意思&#xff08;简称为“信创”&#xff09;。 相信在中国&#xff0c;企业对于“信创化”这个概念并不陌生。「国强则民强」&#xff0c;今年来中国经济的快速发展&#xff0c;受到了各大欧美强国的“卡脖子”操作的影…

CNN(七):ResNeXt-50算法的思考

&#x1f368; 本文为&#x1f517;365天深度学习训练营中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊|接辅导、项目定制 在进行ResNeXt-50实战练习时&#xff0c;我也跟其他学员一样有这个疑惑&#xff0c;如下图所示&#xff1a; 反复查看代码&#xff0c;仍然有…

探讨前后端分离开发的优势、实践以及如何实现更好的用户体验?

随着互联网技术的迅猛发展&#xff0c;前后端分离开发已经成为现代软件开发的一种重要趋势。这种开发模式将前端和后端的开发工作分开&#xff0c;通过清晰的接口协议进行通信&#xff0c;旨在优化开发流程、提升团队协作效率&#xff0c;并最终改善用户体验。本文将深入探讨前…

Elasticsearch——Docker单机部署安装

文章目录 1 简介2 Docker安装与配置2.1 安装Docker2.2 配置Docker镜像加速器2.3 调整Docker资源限制 3 准备Elasticsearch Docker镜像3.1 下载Elasticsearch镜像3.2 自定义镜像配置3.3执行Docker Compose 4 运行Elasticsearch容器4.1 创建Elasticsearch容器4.2 修改配置文件4.3…

Mac 搭建本地服务器

文章目录 一、启动服务器二、添加文件到本地服务三、手机/其他电脑 访问本机服务器 MacOS 自带Apatch 服务器。所以我这里选择Apatch服务器搭建 一、启动服务器 在safari中输入 http://127.0.0.1/ &#xff0c;如果页面出现 it works&#xff0c;则代表访问成功。启动服务器 …

开开心心带你学习MySQL数据库之第五篇

&#x1f63a;欢迎来到我的博客, 记得点赞&#x1f44d;收藏⭐️留言✍️&#x1f431; &#x1f409;做为一个怪兽&#xff0c;我的目标是少消灭一个奥特曼&#x1f409; &#x1f4d6;希望我写的博客对你有所帮助,如有不足,请指正&#x1f4d6; chatgpt 是否能够代替程序猿?…

AI时代:探索机器学习与深度学习的融合之旅

文章目录 1. 机器学习和深度学习简介1.1 机器学习1.2 深度学习 2. 为什么融合是必要的&#xff1f;2.1 数据增强2.2 模型融合 3. 深入分析&#xff1a;案例研究3.1 传统机器学习方法3.2 深度学习方法3.3 融合方法 4. 未来展望结论 &#x1f389;欢迎来到AIGC人工智能专栏~AI时代…

【力扣每日一题】2023.9.6 最深叶节点的最近公共祖先

目录 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 代码&#xff1a; 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 题目给我们一棵二叉树&#xff0c;让我们找出所有最深叶子节点的最近公共祖先。 我们一步一步剖析&#xff0c;我们先找出最深叶子节点&…