美文网首页
Fragment解析(1)

Fragment解析(1)

作者: Horps | 来源:发表于2022-12-01 21:17 被阅读0次
  • 写在前面

    本文基于androidx相关源码,也就是在androidx.fragment.app包下面的相关类,基于继承自AppCompatActivity的使用,AppCompatActivity继承自FragmentActivity,而FragmentActivity内部管理着Fragment相关;如果是继承自Activity的则在Activity内部使用的是android.app包下的相关类,Activity里面也会有一个FragmentController对象mFragments,但它是android.app包下的,不是同一个类。调用Activity的相关方法时,这两个mFragments的逻辑都会执行,这种看似重复主要是为了兼容。

    本文主要分析fragment的xml加载流程、生命周期以及在这个过程中和和Activity的联系。

  • 建立连接

    首先,需要建立Activity和Fragment的连接,在设计上,Activity并不是直接管理Fragment的,而是通过一个叫做FragmetnController的对象mFragements来管理:

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

    在FragmentActivity的构造方法里会调用init方法:

    private void init() {
          ... ...
        addOnContextAvailableListener(context -> mFragments.attachHost(null /*parent*/));
    }
    

    在这里添加了一个监听,addOnContextAvailableListener方法是在其父类ComponentActivity中定义的:

    @Override
    public final void addOnContextAvailableListener(
            @NonNull OnContextAvailableListener listener) {
        mContextAwareHelper.addOnContextAvailableListener(listener);
    }
    
    //ContextAwareHelper中:
    public void addOnContextAvailableListener(@NonNull OnContextAvailableListener listener) {
        if (mContext != null) {
            listener.onContextAvailable(mContext);
        }
        mListeners.add(listener);
    }
    public void dispatchOnContextAvailable(@NonNull Context context) {
        mContext = context;
        for (OnContextAvailableListener listener : mListeners) {
            listener.onContextAvailable(context);
        }
    }
    

    在ComponentActivity的onCreate方法中会调用:

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        ... ...
        mContextAwareHelper.dispatchOnContextAvailable(this);
        super.onCreate(savedInstanceState);
        ... ... 
    }
    

    因此,在Activity的onCreate时会调用mFragments.attachHost方法:

    public void attachHost(@Nullable Fragment parent) {
        mHost.mFragmentManager.attachController(
                mHost, mHost /*container*/, parent);
    }
    

    mHost就是传入的HostCallbacks。mFragmentManager在其父类FragmentHostCallback中定义:

    final FragmentManager mFragmentManager = new FragmentManagerImpl();
    
    /**
     * Package private implementation of FragmentManager.
     * <p>
     * All of the logic that used to be in this class has moved
     * to {@link FragmentManager} itself.
     * <p>
     * Developers should never instantiate a FragmentManager
     * directly, but instead operate via the APIs on
     * {@link FragmentActivity}, {@link Fragment}, or
     * {@link FragmentController} to retrieve an instance.
     */
    class FragmentManagerImpl extends FragmentManager {
    }
    

    这是个空实现,根据注释,我们知道逻辑都放在了FragmentManager中,在FragmentManager的attachController方法中:

    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) {
            addFragmentOnAttachListener(new FragmentOnAttachListener() {
                @SuppressWarnings("deprecation")
                @Override
                public void onAttachFragment(@NonNull FragmentManager fragmentManager,
                        @NonNull Fragment fragment) {
                    parent.onAttachFragment(fragment);
                }
            });
        } else if (host instanceof FragmentOnAttachListener) {
            addFragmentOnAttachListener((FragmentOnAttachListener) host);
        }
          ... ...
    }
    

    到这里,我们知道了每一个Activity都有自己独立的FragmentController,FragmentController持有独立的HostCallbacks,其父类中持有一个独立的FragmentManager实例,它的mContainer是HostCallbacks,因此每个Activity调用getSupportFragmentManager方法获取的FragmentManager都是属于当前Activity本身的。

    至此,Activity和FragmentController关联起来了,下面看看Fragment是如何创建的。

    我们知道,Fragment有两种创建方式,一种是通过xml定义,另一种是通过FragmentTransaction调用commit方法,下面我们分别从两个方向分析一下是如何实现的。

  • 通过xml加载Fragment

    我们知道,如果Fragment在xml中定义的话,就会走到LayoutInflater的inflate流程,在LayoutInflater的inflate解析流程(详情见《LayoutInflater解析》一文 )中,没有发现任何解析fragment标签的代码,但是在tryCreateView方法里预留了mFactory、mFactory2这样的接口实例,会自动调用它们的onCreateView方法,那Fragment是否是通过它们来从xml中加载的呢?

    按照这个思路,根据tryCreateView内的调用顺序,mFactory2、mFactory和mPrivateFactory会被依次调用,如果前面的Factory创建出实例了则直接返回。mFactory2、mFactory和mPrivateFactory的赋值有两个途径,一个是在LayoutInflater的双参数的构造方法里通过克隆另一个LayoutInflater的Factory,另一种是通过相关的setXxx方法设置。在《LayoutInflater解析》中我们发现通过LayoutInflater.from方法获取的实例没有通过构造函数方式对Factory赋值,所以只能是在某个地方通过相关的set方法赋值的。

    按照顺序,首先看看LayoutInflater的setFactory2方法会不会在哪里调用了呢?

    搜了一下有很多地方,但是如果想要在加载布局的时候就已经可以使用Factory,通过分析,我们锁定了LayoutInflaterCompat的其中一个setFactory2重载方法:

    public static void setFactory2(
            @NonNull LayoutInflater inflater, @NonNull LayoutInflater.Factory2 factory) {
        inflater.setFactory2(factory);
    
        if (Build.VERSION.SDK_INT < 21) {
            final LayoutInflater.Factory f = inflater.getFactory();
            if (f instanceof LayoutInflater.Factory2) {
                // The merged factory is now set to getFactory(), but not getFactory2() (pre-v21).
                // We will now try and force set the merged factory to mFactory2
                forceSetFactory2(inflater, (LayoutInflater.Factory2) f);
            } else {
                // Else, we will force set the original wrapped Factory2
                forceSetFactory2(inflater, factory);
            }
        }
    }
    

    为什么锁定这个方法,是因为我们发现这个方法会在AppCompatDelegateImpl的installViewFactory方法中调用,先看AppCompatDelegateImpl的构造函数:

    @ContentView
    public AppCompatActivity(@LayoutRes int contentLayoutId) {
        super(contentLayoutId);
        initDelegate();
    }
    private void initDelegate() {
        ...
        addOnContextAvailableListener(new OnContextAvailableListener() {
            @Override
            public void onContextAvailable(@NonNull Context context) {
                final AppCompatDelegate delegate = getDelegate();
                delegate.installViewFactory();
                ...
            }
        });
    }
    

    可以看到,在AppCompatActivity的构造函数里注册了Context监听:

    @Override
    public final void addOnContextAvailableListener(
            @NonNull OnContextAvailableListener listener) {
        mContextAwareHelper.addOnContextAvailableListener(listener);
    }
    

    在ComponentActivity的onCreate方法里会分发通知:

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        ...
        mContextAwareHelper.dispatchOnContextAvailable(this);
        super.onCreate(savedInstanceState);
        ...
    }
    

    我们知道,加载xml布局就是在setContenView流程里调用的,因此会先于加载xml布局调用installViewFactory方法,这符合我们前面的猜想需求:

    @Override
    public void installViewFactory() {
        LayoutInflater layoutInflater = LayoutInflater.from(mContext);
        if (layoutInflater.getFactory() == null) {
            LayoutInflaterCompat.setFactory2(layoutInflater, this);
        } ...
    }
    

    所以就是在这里设置的mFactory2,所以LayoutInflater的mFactory2是AppCompatDelegateImpl,查找了AppCompatDelegateImpl重写的onCreateView方法,里面并没有找到和fragment相关的解析代码,很显然这个类不是解析fragment相关类的地方。

    于是我们只剩下了一个地方: mPrivateFactory

    经过查找(使用IDE自动关联无法跳转,用ctrl+H全局搜索),我们发现在Activity的attach方法里有一句:

    mWindow.getLayoutInflater().setPrivateFactory(this);
    

    PhoneWindow的构造方法里初始化了LayoutInflater:

    public PhoneWindow(@UiContext Context context) {
        super(context);
        mLayoutInflater = LayoutInflater.from(context);
        ...
    }
    

    之后PhoneWindow的setContentView逻辑中使用的mLayoutInflater正是这个已经初始化好的LayoutInflater:

    public void setContentView(int layoutResID) {
        ...
        mLayoutInflater.inflate(layoutResID, mContentParent);
        ...
    }
    

    回到xml加载流程中,由于FragmentActivity作为子类实现了它的onCreateView方法,因此此时mPrivateFactory.onCreateView方法就会走到FragmentActivity的onCreateView方法里,在它的实现里会调用dispatchFragmentsOnCreateView方法:

    final View dispatchFragmentsOnCreateView(@Nullable View parent, @NonNull String name,
            @NonNull Context context, @NonNull AttributeSet attrs) {
        return mFragments.onCreateView(parent, name, context, attrs);
    }
    
    public View onCreateView(@Nullable View parent, @NonNull String name, @NonNull Context context,
            @NonNull AttributeSet attrs) {
        return mHost.mFragmentManager.getLayoutInflaterFactory()
                .onCreateView(parent, name, context, attrs);
    }
    

    getLayoutInflaterFactory得到的是FragmentManager的mLayoutInflaterFactory:

    private final FragmentLayoutInflaterFactory mLayoutInflaterFactory =
            new FragmentLayoutInflaterFactory(this);
    

    FragmentLayoutInflaterFactory的onCreateView方法如下:

    public View onCreateView(@Nullable final View parent, @NonNull String name,
            @NonNull Context context, @NonNull AttributeSet attrs) {
          //首先会尝试创建FragmentContainerView,熟悉navigation的话会对他很熟悉
        if (FragmentContainerView.class.getName().equals(name)) {
            return new FragmentContainerView(context, attrs, mFragmentManager);
        }
          //其次,加载<fragment/>标签
        if (!"fragment".equals(name)) {
            return null;
        }
          //优先从fragment标签的class属性中取得Fragment的类名
        String fname = attrs.getAttributeValue(null, "class");
        TypedArray a =  context.obtainStyledAttributes(attrs, R.styleable.Fragment);
          //如果class属性没设置的话再从android:name中取Fragment的类名
        if (fname == null) {
            fname = a.getString(R.styleable.Fragment_android_name);
        }
          //取到Fragment设置的id和tag(如果有的话)
        int id = a.getResourceId(R.styleable.Fragment_android_id, View.NO_ID);
        String tag = a.getString(R.styleable.Fragment_android_tag);
        a.recycle();
          //必须是继承自Fragment的类
        if (fname == null || !FragmentFactory.isFragmentClass(context.getClassLoader(), fname)) {
            // Invalid support lib fragment; let the device's framework handle it.
            // This will allow android.app.Fragments to do the right thing.
            return null;
        }
    
        int containerId = parent != null ? parent.getId() : 0;
        if (containerId == View.NO_ID && id == View.NO_ID && tag == null) {
            throw new IllegalArgumentException(attrs.getPositionDescription()
                    + ": Must specify unique android:id, android:tag, or "
                    + "have a parent with an id for " + fname);
        }
    
        // 依次按照id、tag和containerId尝试从mFragmentManager中获取已有的Fragment
        Fragment fragment = id != View.NO_ID ? mFragmentManager.findFragmentById(id) : null;
        if (fragment == null && tag != null) {
            fragment = mFragmentManager.findFragmentByTag(tag);
        }
        if (fragment == null && containerId != View.NO_ID) {
            fragment = mFragmentManager.findFragmentById(containerId);
        }
    
        final FragmentStateManager fragmentStateManager;
          //如果FragmentManager中没找到则说明未创建过,则开始创建
        if (fragment == null) {
              //没什么好说的,反射创建实例
            fragment = mFragmentManager.getFragmentFactory().instantiate(
                    context.getClassLoader(), fname);
            fragment.mFromLayout = true;
            fragment.mFragmentId = id != 0 ? id : containerId;
            fragment.mContainerId = containerId;
            fragment.mTag = tag;
            fragment.mInLayout = true;
            fragment.mFragmentManager = mFragmentManager;
            fragment.mHost = mFragmentManager.getHost();
            fragment.onInflate(mFragmentManager.getHost().getContext(), attrs,
                    fragment.mSavedFragmentState);
            fragmentStateManager = mFragmentManager.addFragment(fragment);
            if (FragmentManager.isLoggingEnabled(Log.VERBOSE)) {
                Log.v(FragmentManager.TAG, "Fragment " + fragment + " has been inflated via "
                        + "the <fragment> tag: id=0x" + Integer.toHexString(id));
            }
    
        } else if(...){...}
        else {
            // 如果已存在
            fragment.mInLayout = true;
            fragment.mFragmentManager = mFragmentManager;
            fragment.mHost = mFragmentManager.getHost();
            fragment.onInflate(mFragmentManager.getHost().getContext(), attrs,
                    fragment.mSavedFragmentState);
            fragmentStateManager = mFragmentManager.createOrGetFragmentStateManager(fragment);
            }
        }
          ...
        fragment.mContainer = (ViewGroup) parent;
    
        // 其实如果是第一次加载的fragment的话,moveToExpectedState不会产生什么影响
        fragmentStateManager.moveToExpectedState();
        // 2) Create the Fragment's view despite not always moving to ACTIVITY_CREATED
        fragmentStateManager.ensureInflatedView();
          ...
        if (id != 0) {
            fragment.mView.setId(id);
        }
        if (fragment.mView.getTag() == null) {
            fragment.mView.setTag(tag);
        }
        // Fragments added via the <fragment> tag cannot move above VIEW_CREATED
        // during inflation. Instead, we'll wait for the view to be attached to
        // window and its parent view and trigger moveToExpectedState() at that point.
        fragment.mView.addOnAttachStateChangeListener(
                new View.OnAttachStateChangeListener() {
                    @Override
                    public void onViewAttachedToWindow(View v) {
                        Fragment fragment = fragmentStateManager.getFragment();
                        fragmentStateManager.moveToExpectedState();
                        SpecialEffectsController controller = SpecialEffectsController
                                .getOrCreateController((ViewGroup) fragment.mView.getParent(),
                                        mFragmentManager);
                        controller.forceCompleteAllOperations();
                    }
    
                    @Override
                    public void onViewDetachedFromWindow(View v) { }
                }
        );
        return fragment.mView;
    }
    

    可以看到,xml中定义的fragment标签就是在这里变成Fragment实例的,FragmentManager的findViewByXxx系列方法如下:

    public Fragment findFragmentById(@IdRes int id) {
        return mFragmentStore.findFragmentById(id);
    }
    public Fragment findFragmentByTag(@Nullable String tag) {
        return mFragmentStore.findFragmentByTag(tag);
    }
    ...etc...
    

    不管是按什么方式查找都是从mFragmentStore中取的,mFragmentStore是FragmentStore实例。

    再来看addFragment方法:

    FragmentStateManager addFragment(@NonNull Fragment fragment) {
        ...
        FragmentStateManager fragmentStateManager = createOrGetFragmentStateManager(fragment);
        fragment.mFragmentManager = this;
        mFragmentStore.makeActive(fragmentStateManager);
        if (!fragment.mDetached) {
            mFragmentStore.addFragment(fragment);
            fragment.mRemoving = false;
            if (fragment.mView == null) {
                fragment.mHiddenChanged = false;
            }
            if (isMenuAvailable(fragment)) {
                mNeedMenuInvalidate = true;
            }
        }
        return fragmentStateManager;
    }
    

    mFragmentStore.addFragment方法如下:

    void addFragment(@NonNull Fragment fragment) {
        if (mAdded.contains(fragment)) {
            throw new IllegalStateException("Fragment already added: " + fragment);
        }
        synchronized (mAdded) {
            mAdded.add(fragment);
        }
        fragment.mAdded = true;
    }
    

    可见,fragment是被添加到FragmentStore的mAdded数组里了,findViewByXxx方法就是从这取的。makeActive方法把根据当前fragment创建的FragmentStateManager实例放入FragmentStroe的mActive中:

    void makeActive(@NonNull FragmentStateManager newlyActive) {
        Fragment f = newlyActive.getFragment();
        if (containsActiveFragment(f.mWho)) {
            return;
        }
        mActive.put(f.mWho, newlyActive);
        ...
    }
    

    f.mWho是随机生成的UUID标志,确保唯一性。

    然后会拿到当前fragment的FragmentStateManager(createOrGetFragmentStateManager方法会从FragmentStore中尝试取缓存中的,没取到就创建新的),然后调用它的moveToExpectedState方法:

    void moveToExpectedState() {
        ...
        try {
              ...
            boolean stateWasChanged = false;
            int newState;
            while ((newState = computeExpectedState()) != mFragment.mState) {
                stateWasChanged = true;
                if (newState > mFragment.mState) {
                    // 如果Fragment的state小于mFragmentManager的state了则生命周期方法往上依次调用,比如onAttach->onCreate->onCreateView...
                    int nextStep = mFragment.mState + 1;//+1是因为状态是int,状态间差值为1
                    switch (nextStep) {
                        case Fragment.ATTACHED:
                            attach();
                            break;
                        case Fragment.CREATED:
                            create();
                            break;
                        case Fragment.VIEW_CREATED:
                            ensureInflatedView();
                            createView();
                            break;
                        case Fragment.AWAITING_EXIT_EFFECTS:
                            activityCreated();
                            break;
                        case Fragment.ACTIVITY_CREATED:
                            if (mFragment.mView != null && mFragment.mContainer != null) {
                                SpecialEffectsController controller = SpecialEffectsController
                                        .getOrCreateController(mFragment.mContainer,
                                                mFragment.getParentFragmentManager());
                                int visibility = mFragment.mView.getVisibility();
                                SpecialEffectsController.Operation.State finalState =
                                        SpecialEffectsController.Operation.State.from(visibility);
                                controller.enqueueAdd(finalState, this);
                            }
                            mFragment.mState = Fragment.ACTIVITY_CREATED;
                            break;
                        case Fragment.STARTED:
                            start();
                            break;
                        case Fragment.AWAITING_ENTER_EFFECTS:
                            mFragment.mState = Fragment.AWAITING_ENTER_EFFECTS;
                            break;
                        case Fragment.RESUMED:
                            resume();
                            break;
                    }
                } else {
                    // 如果Fragment的state超过mFragmentManager的state了则生命周期方法往下依次调用,比如onDestroyView->onCreateView...
                    int nextStep = mFragment.mState - 1;
                    switch (nextStep) {
                        //同上
                        ...
                    }
                }
            }
            if (!stateWasChanged && mFragment.mState == Fragment.INITIALIZING) {
                if (mFragment.mRemoving && !mFragment.isInBackStack() && !mFragment.mBeingSaved) {                         ...
                    mFragment.initState();
                }
            }
              ... 
        } ...
    }
    

    看一下computeExpectedState方法:

    //In Fragment:
    static final int INITIALIZING = -1;          // Not yet attached.
    static final int ATTACHED = 0;               // Attached to the host.
    static final int CREATED = 1;                // Created.
    static final int VIEW_CREATED = 2;           // View Created.
    static final int AWAITING_EXIT_EFFECTS = 3;  // Downward state, awaiting exit effects
    static final int ACTIVITY_CREATED = 4;       // Fully created, not started.
    static final int STARTED = 5;                // Created and started, not resumed.
    static final int AWAITING_ENTER_EFFECTS = 6; // Upward state, awaiting enter effects
    static final int RESUMED = 7;                // Created started and resumed.
    //因为Fragment通常就是用来显示出来的,所以默认都是RESUMED,也是int值最大的状态
    Lifecycle.State mMaxState = Lifecycle.State.RESUMED;
    
    //In FragmentStateManager:
    int computeExpectedState() {
        ...
        int maxState = mFragmentManagerState;
        // 每一个Fragment都有一个maxState,switch语句块是限制不能超过最大状态,其实就是生命周期长度的限制
        switch (mFragment.mMaxState) {
            case RESUMED:
                // 如果mFragment.mMaxState是RESUMED,则mFragmentManagerState肯定不会超出,因为RESUMED是最大(最后的)的状态
                break;
            case STARTED:
                maxState = Math.min(maxState, Fragment.STARTED);
                break;
            case CREATED:
                maxState = Math.min(maxState, Fragment.CREATED);
                break;
            case INITIALIZED:
                maxState = Math.min(maxState, Fragment.ATTACHED);
                break;
            default:
                maxState = Math.min(maxState, Fragment.INITIALIZING);
        }
          //如果是从xml中加载的情况
          if (mFragment.mFromLayout) {
            if (mFragment.mInLayout) {
                  //修改成至少是VIEW_CREATED状态
                maxState = Math.max(mFragmentManagerState, Fragment.VIEW_CREATED);
                  //此时还未创建mView,因此不会走下面的
                  if (mFragment.mView != null && mFragment.mView.getParent() == null) {
                    maxState = Math.min(maxState, Fragment.VIEW_CREATED);
                }
            } else {
                ...
            }
        }
        ...
        return maxState;
    }
    

    mFragmentManagerState是FragmentManager的状态,它由Activity来控制,当Activty相关生命周期方法触发FragmentManager的mFragmentManagerState状态改变时,其内部的每个Fragmetn都应该同步成和FragmentManager的状态一致,但是每个Fragment都有自己的maxState,标志着其当前状态不能超过这个状态,因此computeExpectedState方法就是根据限制获取一个合理范围内的状态。

    继续往下看,如果新状态不是Fragment的当前状态,则需要把Fragment的状态更新到最新状态,通过 if (newState > mFragment.mState) 判断会走两个相反的分支(分别是创建和销毁两个方向的状态递进),因为Fragment的当前状态可能低于最新状态也可能超过了最新状态,又因为状态值用int型表示,于是通过 int nextStep = mFragment.mState + 1(或者-1) 来逐渐向新状态靠近,直到变成新状态。

    在变成新状态的过程中,通过while循环,会逐渐调用过程中的生命周期方法,比如从初始化状态变成CREATED状态时会依次调用到attach、create方法,这些方法的内部分别会调用mFragment.performAttach、mFragment.performCreate方法,这些方法内又会分别调用到Fragment的onAttach、onCreate方法。因此,FragmentStateManager的moveToExpectedState方法是Fragment生命周期方法的触发入口。

    因为我们通常是在调用完super.onCreate方法之后调用setContentView,所以mFragments的dispatchCreate方法是先执行的,因此在加载xml内容之前FragmentManager的state就变成了CREATED,所以computeExpectedState方法理应是该返回CREATED,但是if (mFragment.mFromLayout) 分支会把xml加载的状态变成VIEW_CREATED,这样while循环中其实会调用到createView,但是createView中其实此时不会去调用Fragment的onCreateView流程:

    if (mFragment.mFromLayout) {
        // This case is handled by ensureInflatedView(), so there's nothing
        // else we need to do here.
        return;
    }
    

    newState作为VIEW_CREATED回到while循环,很明显mFragment.mState需要从INITIALIZING变成VIEW_CREATED,所以这里会执行attach、create和createView方法,又因为createView方法不会执行任何从xml中加载的逻辑,所以此时只调用了onAttach和onCreate方法

    至此,我们看到了onAttach、onCreate方法被调用了,还没有看到调用Fragment的onCreatView方法,而新创建的Fragment又不会走到moveToExpectedState的switch中的VIEW_CREATED状态分支那里调用createView,那么fragment的view又是在哪里产生的呢?

    别着急,回到FragmentLayoutInflaterFactory的onCreateView方法,moveToExpectedState方法下一行执行了 fragmentStateManager.ensureInflatedView()

    void ensureInflatedView() {
        if (mFragment.mFromLayout && mFragment.mInLayout && !mFragment.mPerformedCreateView) {
            ...
            mFragment.performCreateView(mFragment.performGetLayoutInflater(
                    mFragment.mSavedFragmentState), null, mFragment.mSavedFragmentState);
            if (mFragment.mView != null) {
                ...
                mFragment.mView.setTag(R.id.fragment_container_view_tag, mFragment);
                if (mFragment.mHidden) mFragment.mView.setVisibility(View.GONE);
                mFragment.performViewCreated();
                ...
                mFragment.mState = Fragment.VIEW_CREATED;
            }
        }
    }
    

    我们看到performCreateView方法在这里调用了,这个方法内部会调用:

    mView = onCreateView(inflater, container, savedInstanceState);
    

    可以看到,Fragment的onCreateView就是在这里调用的。然后会调用 mFragment.performViewCreated() 来回调onViewCreated方法。最后修改mFragment.mState为Fragment.VIEW_CREATED。

    到这里,我们的xml加载Fragment过程就分析完了。

  • FragmentActivity的生命周期方法

    在FragmentActivity中的生命周期方法中会调用FragmentController的相关方法通知Fragment的生命周期状态改变。

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    
        mFragmentLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
        mFragments.dispatchCreate();
    }
    

    在FragmentActivity的onCreate方法中会调用mFragments的dispatchCreate方法,内部调用的是FragmentManager的dispatchCreate方法:

    void dispatchCreate() {
        mStateSaved = false;
        mStopped = false;
        mNonConfig.setIsStateSaved(false);
        dispatchStateChange(Fragment.CREATED);
    }
    

    其他的生命周期方法也是类似,都是在Activity的相关生命周期方法中调用的,比如,onActivityCreated和onStart都是在Activity的onStart方法中先后调用的:

    @Override
    protected void onStart() {
          ...
        super.onStart();
          ...
        if (!mCreated) {
            mCreated = true;
            mFragments.dispatchActivityCreated();
        }
          
        mFragments.execPendingActions();
          ...
        mFragments.dispatchStart();
    }
    

    最终会调用FragmentManager的dispatchActivityCreated方法和dispatchStart方法:

    void dispatchActivityCreated() {
        mStateSaved = false;
        mStopped = false;
        mNonConfig.setIsStateSaved(false);
        dispatchStateChange(Fragment.ACTIVITY_CREATED);
    }
    void dispatchStart() {
        mStateSaved = false;
        mStopped = false;
        mNonConfig.setIsStateSaved(false);
        dispatchStateChange(Fragment.STARTED);
    }
    

    可见最后都是调用dispatchStateChange方法,下面我们开始解析dispatchStateChange流程。

  • dispatchStateChange流程

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

    可以看到,这里首先会把mFragmentStore中mActive管理的FragmentStateManager的mFragmentManagerState都修改成新状态:

    void dispatchStateChange(int state) {
        for (FragmentStateManager fragmentStateManager : mActive.values()) {
            if (fragmentStateManager != null) {
                fragmentStateManager.setFragmentManagerState(state);
            }
        }
    }
    

    然后调用moveToState方法:

    void moveToState(int newState, boolean always) {
        ...
        mCurState = newState;
        mFragmentStore.moveToExpectedState();
        ...
    }
    

    FragmentStroe的moveToExpectedState方法如下:

    void moveToExpectedState() {
        for (Fragment f : mAdded) {
            FragmentStateManager fragmentStateManager = mActive.get(f.mWho);
            if (fragmentStateManager != null) {
                fragmentStateManager.moveToExpectedState();
            }
        }
        for (FragmentStateManager fragmentStateManager : mActive.values()) {
            if (fragmentStateManager != null) {
                fragmentStateManager.moveToExpectedState();
                ...
            }
        }
    }
    

    可见,最终还是会调用每个FragmentStateManager的moveToExpectedState方法,这个方法我们之前已经分析过了,就是把其管理的Fragment的状态修改成和FragmentManager的状态一致,状态更改过程中会依次调用对应生命周期方法。

  • 总结

    • xml中的Fragment是如何加载的

      1. 在Activity创建时调用的attach方法中会初始化PhoneWindow对象mWindow,mWindow初始化时会初始化一个LayoutInflater,然后会给这个LayoutInflater设置mPrivateFactory为Activity本身:

        mWindow.getLayoutInflater().setPrivateFactory(this);
        
      2. 在进入Activity的onCreate方法之后,会调用setContentView方法,最终会调用到PhoneWindow的setContentView方法,在这个方法中会使用之前构造的LayoutInflater的inflate方法来完成xml布局的解析加载;

      3. 如果是fragment相关的标签,比如fragment标签或者androidx.fragment.app.FragmentContainerView等无法通过通用流程解析的标签,最终都会交给mPrivateFactory来处理;

      4. 通过第一步我们知道mPrivateFactory就是Activity本身,所以mPrivateFactory的onCreateView方法会被Activity的该方法执行,因为FragmentActivity继承了它,所以会走到FragmentActivity的onCreateView方法中;

      5. FragmentActivity的onCreateView方法中会调用dispatchFragmentsOnCreateView方法,最终它会调用到一个叫FragmentLayoutInflaterFactory的onCreateView方法中,在这个方法里实现了解析fragment相关类的逻辑。

    • Fragment的生命周期方法触发顺序

      1. FragmentController的dispatchCreate方法会首先被调用,但此时因为还没有加载任何的fragment,所以此时只会修改FragmentManager的状态成CREATED;
      2. 然后setContentView的inflate流程开始,会把加载的fragment的状态都变成之前FragmentManager的状态,也就是CREATED(xml加载时computeExpectedState方法返回的是VIEW_CREATED,但是因为createView方法中不会执行从xml中加载这种情况的任何逻辑,所以虽然状态变了,但是onCreateView方法并没有调用);
      3. 状态改变过程通过while循环和fragment的state值+1(如果是销毁的过程则是-1)来实现的,比如从INITIALIZING变成CREATED会依次调用onAttached、onCreate;
      4. 根据第3步的算法,在第2步的过程中会调用到onAttach和onCreate方法,最后会调用ensureInflatedView方法触发onCreateView方法和onViewCreated方法;
      5. 上述两步都是Activity的onCreate中的工作,按照Activity的生命周期,接下来会调用onStart方法,它先会调用FragmentController的dispatchActivityCreated方法(只会调用一次),这会改变FragmentManager的状态变成ACTIVITY_CREATED,因此会调用onActivityCreated方法。然后还会调用dispatchStart方法触发onStart方法;
      6. 之后就是onResume,如果是销毁的过程也都是类似的流程。

相关文章

网友评论

      本文标题:Fragment解析(1)

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