美文网首页Android
Fragment源码简析(二)

Fragment源码简析(二)

作者: andev009 | 来源:发表于2018-01-09 13:45 被阅读54次

    上一篇 Fragment源码简析(一)
    接上一篇

    //BackStackRecord中executeOps方法最后调用到这里
    mManager.moveToState(mManager.mCurState, true);
    
    final class FragmentManagerImpl extends FragmentManager implements LayoutInflater.Factory2 {
           int mCurState = Fragment.INITIALIZING;
           //只看主流程代码
           void moveToState(int newState, boolean always) {
                  mCurState = newState;
                   for (int i = 0; i < numAdded; i++) {
                       Fragment f = mAdded.get(i);
                       moveFragmentToExpectedState(f);
                   }
                   ...........
           }
    }
    

    moveFragmentToExpectedState又调到了moveToState的另一个重载方法,很长。
    这里先停下,回到上一篇里的问题,FragmentManager的mHost为什么就是FragmentController的mHost呢?反推看看。在FragmentManagerImpl类里看到mHost被赋值的方法:

    final class FragmentManagerImpl extends FragmentManager{
          public void attachController(FragmentHostCallback host,
                FragmentContainer container, Fragment parent) {
                mHost = host;
                mContainer = container;
                mParent = parent;
          }
          ................
    }
    
    public class FragmentController {
         public void attachHost(Fragment parent) {
            mHost.mFragmentManager.attachController(mHost, mHost /*container*/, parent);
         }
         ....................
    }
    
    public class FragmentActivity extends BaseFragmentActivityApi16{
     @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            mFragments.attachHost(null /*parent*/);
            super.onCreate(savedInstanceState);
            ..........................
            mFragments.dispatchCreate();
         }
         ............
    }
    

    这样了解到从前往后的流程其实是:

    FragmentActivity(onCreate) ->FragmentController(attachHost)->FragmentManagerImpl(attachController)
    
    

    源头来自于FragmentActivity的onCreate方法,在onCreate最后调用了FragmentController的dispatchCreate,在FragmentController里有很多dispatch方法。比如:

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

    CREATED,ACTIVITY_CREATED这些都是Fragment的状态,状态一共是下面几种:

    static final int INITIALIZING = 0;     // Not yet created.
    static final int CREATED = 1;          // Created.
    static final int ACTIVITY_CREATED = 2; // The activity has finished its creation.
    static final int STOPPED = 3;          // Fully created, not started.
    static final int STARTED = 4;          // Created and started, not resumed.
    static final int RESUMED = 5;          // Created started and resumed.
    
    int mState = INITIALIZING;
    

    上面这些dispatch方法去了dispatchStateChange方法:

    private void dispatchStateChange(int nextState) {
            try {
                mExecutingActions = true;
                moveToState(nextState, false);//比如CREATED,ACTIVITY_CREATED
            } finally {
                mExecutingActions = false;
            }
            execPendingActions();
    }
    

    也是走到了moveToState方法:

    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) {
                // 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);
                                }
                                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) {
                switch (f.mState) {
                    case Fragment.RESUMED:
                        if (newState < Fragment.RESUMED) {
                            if (DEBUG) Log.v(TAG, "movefrom RESUMED: " + f);
                            f.performPause();
                            dispatchOnFragmentPaused(f, false);
                        }
                        // fall through
                    case Fragment.STARTED:
                        if (newState < Fragment.STARTED) {
                            if (DEBUG) Log.v(TAG, "movefrom STARTED: " + f);
                            f.performStop();
                            dispatchOnFragmentStopped(f, false);
                        }
                        // fall through
                    case Fragment.STOPPED:
                        if (newState < Fragment.STOPPED) {
                            if (DEBUG) Log.v(TAG, "movefrom STOPPED: " + f);
                            f.performReallyStop();
                        }
                        // fall through
                    case Fragment.ACTIVITY_CREATED:
                        if (newState < Fragment.ACTIVITY_CREATED) {
                            if (DEBUG) Log.v(TAG, "movefrom ACTIVITY_CREATED: " + f);
                            if (f.mView != null) {
                                // Need to save the current view state if not
                                // done already.
                                if (mHost.onShouldSaveFragmentState(f) && f.mSavedViewState == null) {
                                    saveFragmentViewState(f);
                                }
                            }
                            f.performDestroyView();
                            dispatchOnFragmentViewDestroyed(f, false);
                            if (f.mView != null && f.mContainer != null) {
                                // Stop any current animations:
                                f.mView.clearAnimation();
                                f.mContainer.endViewTransition(f.mView);
                                AnimationOrAnimator anim = null;
                                if (mCurState > Fragment.INITIALIZING && !mDestroyed
                                        && f.mView.getVisibility() == View.VISIBLE
                                        && f.mPostponedAlpha >= 0) {
                                    anim = loadAnimation(f, transit, false,
                                            transitionStyle);
                                }
                                f.mPostponedAlpha = 0;
                                if (anim != null) {
                                    animateRemoveFragment(f, anim, newState);
                                }
                                f.mContainer.removeView(f.mView);
                            }
                            f.mContainer = null;
                            f.mView = null;
                            f.mInnerView = null;
                            f.mInLayout = false;
                        }
                        // fall through
                    case Fragment.CREATED:
                        if (newState < Fragment.CREATED) {
                            if (mDestroyed) {
                                // The fragment's containing activity is
                                // being destroyed, but this fragment is
                                // currently animating away.  Stop the
                                // animation right now -- it is not needed,
                                // and we can't wait any more on destroying
                                // the fragment.
                                if (f.getAnimatingAway() != null) {
                                    View v = f.getAnimatingAway();
                                    f.setAnimatingAway(null);
                                    v.clearAnimation();
                                } else if (f.getAnimator() != null) {
                                    Animator animator = f.getAnimator();
                                    f.setAnimator(null);
                                    animator.cancel();
                                }
                            }
                            if (f.getAnimatingAway() != null || f.getAnimator() != null) {
                                // We are waiting for the fragment's view to finish
                                // animating away.  Just make a note of the state
                                // the fragment now should move to once the animation
                                // is done.
                                f.setStateAfterAnimating(newState);
                                newState = Fragment.CREATED;
                            } else {
                                if (DEBUG) Log.v(TAG, "movefrom CREATED: " + f);
                                if (!f.mRetaining) {
                                    f.performDestroy();
                                    dispatchOnFragmentDestroyed(f, false);
                                } else {
                                    f.mState = Fragment.INITIALIZING;
                                }
    
                                f.performDetach();
                                dispatchOnFragmentDetached(f, false);
                                if (!keepActive) {
                                    if (!f.mRetaining) {
                                        makeInactive(f);
                                    } else {
                                        f.mHost = null;
                                        f.mParentFragment = null;
                                        f.mFragmentManager = null;
                                    }
                                }
                            }
                        }
                }
            }
    
            if (f.mState != newState) {
                Log.w(TAG, "moveToState: Fragment state for " + f + " not updated inline; "
                        + "expected state " + newState + " found " + f.mState);
                f.mState = newState;
            }
        }
    

    moveToState很长,可以结合Fragment的生命周期函数看,这里看下Fragment的onCreateView回调后返回的View 怎么加入到之前布局的,在上面case Fragment.CREATED下:

    f.mContainer = container;
    f.mView = f.performCreateView(f.performGetLayoutInflater(
    f.mSavedFragmentState), container, f.mSavedFragmentState);
    if (f.mView != null) {
        if (container != null) {
            container.addView(f.mView);
        }
        if (f.mHidden) {
             f.mView.setVisibility(View.GONE);
        }
     }
    

    原来这么简单,只是调用普通的addView而已,隐藏Fragment也不过是调用普通的setVisibility。把Fragment当做有生命周期管理的复杂View,是不是理解简单点。

    这里简单总结Fragment生命周期是怎么改变的:
    Fragment和FragmentManagerImpl最初的状态是INITIALIZING;当FragmentActivity生命周期改变时,会调用到上面说的dispatch方法改变FragmentManagerImpl当前的状态值mCurState,然后FragmentManagerImpl会遍历Fragment(这里有两个列表mAdded和mActive),通过moveFragmentToExpectedState来调用moveToState改变Fragment当前的状态。

    相关文章

      网友评论

        本文标题:Fragment源码简析(二)

        本文链接:https://www.haomeiwen.com/subject/zrwwnxtx.html