Fragment静态使用生命周期流程详解

Fragment生命周期

如何理解Activity的onCreate执行期间Fragment才从onAttach开始?这个过程是如何进行的?

这个过程的触发方法实际上是Activity的onCreate方法中的setContentView,更准确的说是setContentView触发的LayoutInflater.inflate去解析布局,而Activity自身也是LayoutInflater.Factory的实现类,其内部的onCreateView方法专门负责XML布局中的fragment标签元素的解析,会触发Fragment反射实例化;而之后再FragmentActivity的onCreate方法中对实例化的Fragment调用moveToState进行Fragment状态迁移,从而触发Fragment的生命周期。

Fragmenet与View异同

Fragment更像是一个复杂的ViewGroup,复杂有两点:

  • 有自己的生命周期;
  • 有返回堆栈。

但是Fragment也有自己独特的地方,即哪里用哪里搬、啥时候用啥时候搬;Fragment在使用时会伴随着hide、show、remove、add、replace等事务,从而实现在一个Activity上展现出跳转不同页面的效果,但是实际上只是这一页面上某个区域内部的切换罢了。这就是Fragment不同于ViewGroup的地方 — 频繁的Fragment对象的切换带来的频繁的内容切换,因为ViewGroup通常是固定的,不会被频繁切换

这也就带来了要对Fragment进行复用的需要,因此也就带来了Fragment事务、回退栈的需求。

Fragment与Activity异同

Fragment之所以给人一种像Activity的感觉无非是其具有相似的生命周期,但这也是区别之处:

  • Activity的生命周期由系统控制;

  • Fragment的生命周期伴随着Activity的生命周期方法onXXX的回调,FragmentActivity内部执行mFragmentManager的dispatchXXX方法使得Fragment的状态发生转移,从而发生Fragment的生命周期调用;可以说,Fragment的生命周期是一种应用层面的,被Activity所控制。(Fragment事务的思想正是主动改变Fragment的状态、使得Fragment的状态暂时脱离宿主Activity而存在)。

一、Activity与FragmentManager

Activity中获取FragmentManager并不容易(以下内容都是androidx包下的Fragment相关机制):

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

public FragmentManager getFragmentManager() {
    return mFragments.getFragmentManager();
}
复制代码

可见,Activity中获取FragmentManager并不是一帆风顺的,而是交给了FragmentController对象去获取,而在Activity中FragmentController对象被原地初始化了,接下来就看看初始化的工作:

// FragmentController.java
private final FragmentHostCallback<?> mHost;

public static final FragmentController createController(FragmentHostCallback<?> callbacks) {
    // 实际上就是调用构造器进行初始化,只不过构造器使用private修饰,只能够使用这种静态方式进行
    return new FragmentController(callbacks);
}

private FragmentController(FragmentHostCallback<?> callbacks) {
    mHost = callbacks;
}

public FragmentManager getFragmentManager() {
    // 而其将获取FragmentManager的工作,交给了mHost属性去做,该属性在构造器中被传入
    return mHost.getFragmentManagerImpl();
}
复制代码

可以看到,最终获取FragmentManager的调用时mHost进行的,而具体的方法实现就是一开始传入的HostCallbacks的父类 — FragmentHostCallback

//FragmentHostCallback.java
public abstract class FragmentHostCallback<E> extends FragmentContainer {
    
    final FragmentManagerImpl mFragmentManager = new FragmentManagerImpl();
    FragmentManagerImpl getFragmentManagerImpl() {
        return mFragmentManager;
    }
}
复制代码

很清晰,就是初始化的FragmentManagerImpl对象。

备注:实际上浏览==FragmentController==这个类的方法实现可以发现,该类中的所有方法的实现都是mHost.mFragmentManager.XXX,因此,我们可以将FragmentController全当为FragmentManagerImpl来看待!!

二、核心类

核心属性展示:

// FragmentManager.java(androidx)
public abstract class FragmentManager {
	private final ArrayList<OpGenerator> mPendingActions = new ArrayList<>();  // 表示是入栈操作还是出栈操作
	ArrayList<BackStackRecord> mBackStack;  // 回退栈,元素为每次事务commit的BackStackRecord对象
	private final FragmentStore mFragmentStore = new FragmentStore();   // 顾名思义,FragmentManager中管理已经add过的Fragment
    FragmentHostCallback<?> mHost;
    FragmentContainer mContainer;  // FragmentHostCallback为FragmentContainer的实现类
    
    // 三个暂存list,代码执行过程中会使用到,不过执行完就会清除
    // Temporary vars for removing redundant operations in BackStackRecords:
    private ArrayList<BackStackRecord> mTmpRecords;
    private ArrayList<Boolean> mTmpIsPop;
    private ArrayList<Fragment> mTmpAddedFragments;
    
    int mCurState = Fragment.INITIALIZING;  // FragmentManager当前的状态!!
}

// FragmentStore.java
class FragmentStore {
    private final ArrayList<Fragment> mAdded = new ArrayList<>();  // 已经add过的Fragment
    private final HashMap<String, FragmentStateManager> mActive = new HashMap<>();
}
复制代码

三、静态Fragment的加载

静态Fragment是通过在xml布局中使用fragment标签定义的Fragment,其加载过程被定义在Activity的onCreateView方法中,Activity作为LayoutInflater.Factory2接口的实现类,将该方法的实现委托给了mFragments属性执行,通过上文的分析,我们知道在Activity的子类FragmentActivity中,mFragments具体实现类为FragmentController,因此,解析XML中Fragment标签的任务就交给了FragmentController:

//FragmentController.java

public View onCreateView(@Nullable View parent, @NonNull String name, @NonNull Context context,
            @NonNull AttributeSet attrs) {
    return mHost.mFragmentManager.getLayoutInflaterFactory()
                .onCreateView(parent, name, context, attrs);
}
复制代码

同样,这里的mFragmentManager的具体实现类是androidx包下的FragmentManagerImpl,那么加载过程就来到了FragmentManager中:

// FragmentManager.java
private final FragmentLayoutInflaterFactory mLayoutInflaterFactory =
            new FragmentLayoutInflaterFactory(this);

// FragmentLayoutInflaterFactory.java
public View onCreateView(@Nullable View parent, @NonNull String name, @NonNull Context context,
            @NonNull AttributeSet attrs) {
        // 只管解析Fragment
        if (!"fragment".equals(name)) {
            return null;
        }
    
    	// 获取到Fragment的全限定类名
        String fname = attrs.getAttributeValue(null, "class");
        TypedArray a =  context.obtainStyledAttributes(attrs, R.styleable.Fragment);
        if (fname == null) {
            // 获取到Fragment的全限定类名
            fname = a.getString(R.styleable.Fragment_android_name);
        }
    	// id
        int id = a.getResourceId(R.styleable.Fragment_android_id, View.NO_ID);
    	// tag
        String tag = a.getString(R.styleable.Fragment_android_tag);
        a.recycle();
        int containerId = parent != null ? parent.getId() : 0;
        
    	// 优先尝试复用Fragment
    	// 首先通过mFragmentManager的findFragmentById
    	// 其次通过mFragmentManager的findFragmentByTag
    	// 最后通过mFragmentManager使用containerId尝试find
        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);
        }

        // 如果没能复用,那么就instantiate初始化Fragment
        if (fragment == null) {
            fragment = mFragmentManager.getFragmentFactory().instantiate(
                    context.getClassLoader(), fname);
            // 这个标签说明该Fragment对象是从xml文件中加载的Fragment
            fragment.mFromLayout = true;
            fragment.mFragmentId = id != 0 ? id : containerId;
            fragment.mContainerId = containerId;
            fragment.mTag = tag;
            // 表示被添加到了Layout中
            fragment.mInLayout = true;
            fragment.mFragmentManager = mFragmentManager;
            fragment.mHost = mFragmentManager.mHost;
            fragment.onInflate(mFragmentManager.mHost.getContext(), attrs,
                    fragment.mSavedFragmentState);
            // 这里实际上是添加到了mFragmentManager的mFragmentStore中
            mFragmentManager.addFragment(fragment);
            
            // 核心!!进行状态转移!!
            mFragmentManager.moveToState(fragment);

        } 

        // 再次执行moveToState,状态迁移至CREATED
        if (mFragmentManager.mCurState < Fragment.CREATED && fragment.mFromLayout) {
            mFragmentManager.moveToState(fragment, Fragment.CREATED);
        } else {
            mFragmentManager.moveToState(fragment);
        }
        
        if (id != 0) {
            fragment.mView.setId(id);
        }
        if (fragment.mView.getTag() == null) {
            fragment.mView.setTag(tag);
        }
        return fragment.mView;
    }
复制代码

到这里,我们可以小结一下xml布局中的fragment标签的解析过程:

  1. 复用阶段:FragmentManager尝试从FragmentStore中复用已有的Fragment对象,优先级如下
    1. 通过布局中的id属性查找;
    2. 通过布局中的tag属性查找;
    3. 通过containerId查找。
  2. 新建阶段:如果是第一次解析该Fragment,那么FragmentManager将使用FragmentFactory来执行对该Fragment的初始化,具体实现是利用反射调用无参构造器,这也就证实了,自定义Fragment时为何一定要提供一个无参构造器了;在创建出Fragment对象之后,调用mFragmentStrore的add方法将该Fragment保存了起来
  3. 状态迁移阶段:在初始化Fragment时,首先执行一次moveToState,需要将Fragment迁移至FragmentManager默认初始状态Fragment.INITIALIZING;之后,再次执行moveToState,将Fragment迁移至CREATED状态。

另外,值得注意的是,我们知道LayoutInflater解析xml文件返回的都是View,而Fragment本身并不是View的子类;那么,FragmentLayoutInflaterFactory工作在LayoutInflater的体系中,就必须满足要求,因此可以看出上述的onCreateView返回的是fragment的mView属性,因此最终被ViewGroup添加的正是这个mView。从==这里也可以看出Fragment与View的区别:Fragment不是View,他因为Activity的LayoutInflater.Factory2的原因,在layout文件中,单独被Activity拦截解析fragment标签;而LayoutInflater.Factory2工作在LayoutInflater解析文件的体系中,必须满足LayoutInflater的要求,所以其功能实现类FragmentLayoutInflaterFactory在onCreateView中,最终返回的是Fragment的mView属性,利用这种机制,来完成对Fragment的静态使用,使得Fragment能够像一个View一样定义在layout文件中,但是Fragment本身并不是View体系中的一员。同时,Fragment也作为这个mView的持有者和管理者,赋予了mView相对独立的生命周期,使得mView可以暂时detach、attach到Activity中。这是其他普通的ViewGroup或者View所不能做到的。==

Fragment复用 — FragmentStore

上面的过程中,涉及到了Fragment的复用过程,在FragmentManager中,这一过程拆解出来,交给了FragmentStore去实现:

// FragmentManager.java
public Fragment findFragmentById(@IdRes int id) {
    return mFragmentStore.findFragmentById(id);
}

public Fragment findFragmentByTag(@Nullable String tag) {
    return mFragmentStore.findFragmentByTag(tag);
}

Fragment findFragmentByWho(@NonNull String who) {
    return mFragmentStore.findFragmentByWho(who);
}
复制代码

可见,都是交给了FragmentStore去完成:

// FragmentStore.java
private final ArrayList<Fragment> mAdded = new ArrayList<>();  // 已将添加过的Fragment
private final HashMap<String, FragmentStateManager> mActive = new HashMap<>();  // 暂时意义不明

    Fragment findFragmentById(@IdRes int id) {
        // First look through added fragments.
        for (int i = mAdded.size() - 1; i >= 0; i--) {
            Fragment f = mAdded.get(i);
            if (f != null && f.mFragmentId == id) {
                return f;
            }
        }
        // Now for any known fragment.
        for (FragmentStateManager fragmentStateManager : mActive.values()) {
            if (fragmentStateManager != null) {
                Fragment f = fragmentStateManager.getFragment();
                if (f.mFragmentId == id) {
                    return f;
                }
            }
        }
        return null;
    }
复制代码

这里以Byid为例,发现就是遍历对比,没什么特殊的方法。记得,上面在解析完xml中的fragment对象后,将其添加到了FragmentStore中,也就是添加到了上面的mAdded属性中

Fragment初始化 — FragmentFactory

在FragmentManager中有一个mFragmentFactory默认为null,用户可以调用FragmentManager的setFragmentFactory来指定一个FragmentFactory对象,同时还有一个mHostFragmentFactory,而FragmentManager的getFragmentFactory()方法实现如下:

// FragmentManager.java
private FragmentFactory mFragmentFactory = null;
private FragmentFactory mHostFragmentFactory = new FragmentFactory() {
    public Fragment instantiate(@NonNull ClassLoader classLoader, @NonNull String className) {
        return mHost.instantiate(mHost.getContext(), className, null);
    }
};

public FragmentFactory getFragmentFactory() {
    if (mFragmentFactory != null) {
        return mFragmentFactory;
    }
    if (mParent != null) {
            
        return mParent.mFragmentManager.getFragmentFactory();
    }
    return mHostFragmentFactory;
}
复制代码

可见,在没有调用过setFragmentFactory的情况下,最终返回的依然是mHostFragmentFactory,而其内部初始化Fragment使用的是FragmentHostCallback — mHost的instantiate方法,只不过该方法的实现,位于其父类FragmentContainer中:

// FragmentContainer.java
public Fragment instantiate(@NonNull Context context, @NonNull String className,
            @Nullable Bundle arguments) {
    // 使用Fragment的静态方法进行初始化
    return Fragment.instantiate(context, className, arguments);
}

// Fragment.java
public static Fragment instantiate(@NonNull Context context, @NonNull String fname,
            @Nullable Bundle args) {
        try {
            Class<? extends Fragment> clazz = FragmentFactory.loadFragmentClass(
                    context.getClassLoader(), fname);
            // 经典调用无参构造器
            Fragment f = clazz.getConstructor().newInstance();
            if (args != null) {
                args.setClassLoader(f.getClass().getClassLoader());
                f.setArguments(args);
            }
            return f;
        } 
    }
复制代码

又是经典的反射使用,这也就是在自定义Fragment的时候必须要提供一个无参构造器的原因!!

Fragment状态转移 — moveToState

Fragment中mState属性默认是INITIALIZING,同时,Fragment还有一个mMaxState属性,表示Fragment最高能够达到的状态,注意,这个mMaxState为Lifecycle的状态,只不过在Fragment中为这几种状态提供了对应的值,因此我们可以将其当做为Fragment状态,默认为Lifecycle.State.RESUMED对标为Fragment.RESUMED

在FragmentManager中对Fragment进行管理的、实现状态迁移的机制有两种,即对应了两种回调:moveToState(Fragment),moveToState(Fragment, int);后者的机制是将目标Fragment迁移至指定状态,而前者内部回调的后者,只不过第二个参数设置的是Fragment当前的状态mCurState。

除此之外,FragmentManager也有自己的状态,即上面展示的mCurState;同时,FragmentManager也提供了一个moveToState(int, boolean)方法来为自己提供状态转移支持。同时,FragmentManager的mCurState的更改方式,只有通过moveToState(int, boolean)这一种方法

四、静态使用Fragment时,Activity声明周期对Fragment声明周期的影响过程

我们都知道,Activity通过FragmentManager来管理Fragment,并且Fragment的声明周期受Activity的声明周期支配,接下来就探究一下Activity的声明周期回调时,如何影响Fragment的生命周期的。

注意!!一下代码分析的是androidx包下的Fragment与Activity启动机制,除此之外还有一个android包下的Fragment,二者在调用上几乎一模一样,但就是不同的东西,切勿混淆!!

Activity — onCreate

我们先来看看FragmentActivity中对该方法的实现:

// FragmentActivity.java
protected void onCreate(@Nullable Bundle savedInstanceState) {
        ...
        super.onCreate(savedInstanceState);

        
        mFragments.dispatchCreate();
    }
复制代码

通过上文的介绍,我们知道,这里的mFragments属性是一个FragmentController实例,只不过其方法都是委托给FragmentManager去实现的,因此,这里实际上就是调用了FragmentManager的dispatchCreate()方法:

// FragmentManager.java
void dispatchCreate() {
    mStateSaved = false;
    mStopped = false;
    dispatchStateChange(Fragment.CREATED);
}

private void dispatchStateChange(int nextState) {
    try {
        mExecutingActions = true;
        mFragmentStore.dispatchStateChange(nextState);
        // 进行状态迁移,注意,由于是从Activity传递过来的,所以代表的是迁移FragmentManager的状态
        // 因此这里调用的是moveToState(int, boolean)这个方法
        moveToState(nextState, false);
    } finally {
        mExecutingActions = false;
    }
    // 涉及到FragmentManager事务,先不管
    execPendingActions(true);
}
复制代码

关于该方法的实现,以及调用过程,上面展示的很明白;同时,此时我们先只关心moveToState方法的调用。注意,由于是从Activity传递过来的,所以代表的是迁移FragmentManager的状态;因此,这里调用的是moveToState(int, boolean)这个方法;同时,第二个参数传递的是false

// FragmentManager.java
void moveToState(int newState, boolean always) {
    ....
    mCurState = newState;
    ....
}
复制代码

上述源码是本次执行时真正起作用的代码,之所以这么特殊,最核心的一点是:==此时Activity属于onCreate方法刚被调用,setContentView还没有被执行,也就是说layout文件中的Fragment还没有触发解析,因此,此时FragmentManager的mFragmentStore中还没有add任何Fragment。此时,该方的作用只有一个:将FragmentManager的mCurState状态保持与Activity同步,同步为CREATED==。

那么,这会带来什么影响呢?回到Activity的流程中来,setContentView触发FragmentLayoutInflaterFactory解析layout文件中的Fragment标签,实现中有如下部分:

// FragmentLayoutInflaterFactory.java
// 如果没能复用,那么就instantiate初始化Fragment
        if (fragment == null) {
            fragment = mFragmentManager.getFragmentFactory().instantiate(
                    context.getClassLoader(), fname);
            // 这个标签说明该Fragment对象是从xml文件中加载的Fragment
            fragment.mFromLayout = true;
            
            // 表示被添加到了Layout中
            fragment.mInLayout = true;
            
            // 这里实际上是添加到了mFragmentManager的mFragmentStore中
            mFragmentManager.addFragment(fragment);
            
            // 核心!!进行状态转移!!
            mFragmentManager.moveToState(fragment);
        } 
复制代码

对本部分来说,==最重要的就是两步:mFragmentManager.addFragment(fragment)与mFragmentManager.moveToState(fragment)。前者将fragment对象添加到mFragmentStore中,这样,FragmentManager才获得了需要管理的Fragment;最最最重要的是后者,对新建的Fragment执行状态迁移!!同时,由于是对Fragment执行状态迁移,所以这里调用的是moveToState(Fragment)这个签名的方法。==

// FragmentManager.java
void moveToState(@NonNull Fragment f) {
	// 注意刚提到的,此时FragmentManager的mCurState为CREATED!!!
    moveToState(f, mCurState);
}

	void moveToState(@NonNull Fragment f, int newState) {
    	// 由于是对该Fragment第一次执行moveToState,所以fragmentStateManager为null
        // 于是需要进入if语句新建一个
        FragmentStateManager fragmentStateManager = mFragmentStore.getFragmentStateManager(f.mWho);
        if (fragmentStateManager == null) {
            fragmentStateManager = new FragmentStateManager(mLifecycleCallbacksDispatcher, f);
            // 这里为内部属性初始化为了CREATED
            fragmentStateManager.setFragmentManagerState(Fragment.CREATED);
        }
        
        // 当前情况下,就为CREATED
        newState = Math.min(newState, fragmentStateManager.computeMaxState());
        if (f.mState <= newState) {
            switch (f.mState) {
                // 刚刚从xml解析出来fragment,第一次执行moveToState
                // 显然,此时Fragment的mState为INITIALIZING
                case Fragment.INITIALIZING:
                    if (newState > Fragment.INITIALIZING) {
                        ...
                        // 执行完毕后,Fragment的状态变为ATTACHED,因此匹配到下一个case
                        fragmentStateManager.attach(mHost, this, mParent);
                    }
                   
                case Fragment.ATTACHED:
                    if (newState > Fragment.ATTACHED) {
                        // 执行完毕后,Fragment的状态变为了CREATED,因此匹配到下一个case
                        fragmentStateManager.create();
                    }
                    
                case Fragment.CREATED:
                    // newState为CREATED,满足条件,进入if语句
                    if (newState > Fragment.INITIALIZING) {
                        // 执行Fragment的onCreateView以及onViewCreated声明周期回调
                        // 由于这两个声明周期回调没有定义对应的状态
                        // 所以Fragment的mState依然是CREATED
                        fragmentStateManager.ensureInflatedView();
                    }
                    
                    // 由于当前Activity状态为CREATED -- FragmentManager也是
                    // Activity的onCreate流程执行moveToState止步于此
                    if (newState > Fragment.CREATED) {
                        fragmentStateManager.createView(mContainer);
                        fragmentStateManager.activityCreated();
                        fragmentStateManager.restoreViewState();
                    }
               case Fragment.ACTIVITY_CREATED:
            }
        } ...
    }
复制代码

通过上述代码注释,可以看出Activity的生命周期回调是如何影响Fragment生命周期回调的:

  • FragmentManager的生命周期状态与Activity同步:在Activity的onCreate中通过调用mFragments的dispatchCreate方法实现Activity生命周期状态的分发,FragmentManager接收到信号后将自己的状态mCurState与Activity同步;很容易理解,FragmentManager本身就是Activity用来管理Fragment的工具类,其状态自然要依附于Parent;
  • Fragment生命周期受限于Activity(FragmentManager)的声明周期:具体表现为,moveToState(Fragment, int)方法实现中,fragmentStateManager执行不同方法进行Fragment的生命周期方法回调实现Fragment状态转移的时候,都要满足newState>f.mState的条件 — Fragment当前状态小于Activity(FragmentManager)的状态,即Fragment转移后的状态小于等于Activity的当前状态,通俗一点说就是:Fragment能够进行状态转移的前提是,状态转移后Fragment的状态不能超前于Activity(FragmentManager)

至此,Activity的onCreate阶段状态转移过程就看完了,通过上面的代码我们知道了,在Activity的onCreate阶段,Fragment依次执行了onAttach、onCreate、onCreateView、onViewCreated四个生命周期回调

根据上面的讲解,我们可以得到如下调用流程示意:

Activity.onCreate -- begin
    
	Fragment.onAttach
	Fragment.onCreate
	Fragment.onCreateView
	Fragment.onViewCreated
    
Activity.onCreate -- end
复制代码

此时的状态:

  • Activity(FragmentManager):CREATED;
  • Fragment:CREATED。

那么后续的生命周期调用该如何继续呢?

Activity — onStart

同样,我们也来看看onStart的代码实现:

// FragmentActivity.java
@Override
    protected void onStart() {
        super.onStart();

        // 贴心的检查了一下
        if (!mCreated) {
            mCreated = true;
            mFragments.dispatchActivityCreated();
        }
        ..
        // 熟悉的方法调用,只不过这次分发的是start
        mFragments.dispatchStart();
    }
复制代码

话不多说,我们知道执行的结果就是调用了FragmentManager的moveToState(int, boolean):

// FragmentManager.java
	void dispatchStart() {
        mStateSaved = false;
        mStopped = false;
        dispatchStateChange(Fragment.STARTED);
    }
    
    private void dispatchStateChange(int nextState) {
        try {
            mExecutingActions = true;
            mFragmentStore.dispatchStateChange(nextState);
            moveToState(nextState, false);
        } ...
    }
复制代码

熟悉的配方,熟悉的味道。但是虽然调用方法一致,但是运行起来确差多了,因为在onCreate时,Fragment还没有被解析出来,也没有被add进mFragmentStore中,因此moveToState方法只是更改了FragmentManager的mCurState变量;但是此时,Fragment已经被加进来了,我们看看此时moveToState(int, boolean)方法执行的流程:

// FragmentManager.java
void moveToState(int newState, boolean always) {
        // 同步当前的生命周期与Activity一致
        mCurState = newState;

        // 由于Fragment已经被加进来了,所以会对其执行if内部的方法,进行状态迁移
        for (Fragment f : mFragmentStore.getFragments()) {
            moveFragmentToExpectedState(f);
        }

    	...
    }
复制代码

首先,必须要做的是将当前FragmentManager的状态与Activity进行同步;由于解析出的Fragment对象已经加入到了mFragmentStore中,所以会对该Fragment执行moveFragmentToExceptedState方法,顾名思义,该方法最终一定会执行moveToState(Fragment, int)实现Fragment的状态转移。

// FragmentManager.java
	void moveFragmentToExpectedState(@NonNull Fragment f) {
    	// 执行状态转移
        moveToState(f);

    }
复制代码

那么此时执行状态转移,代码执行过程是如何呢?

// FragmentManager.java
void moveToState(@NonNull Fragment f, int newState) {
    	// 此时获取到的便不再是null了
        FragmentStateManager fragmentStateManager = mFragmentStore.getFragmentStateManager(f.mWho);
        // 结果是STARTED
        newState = Math.min(newState, fragmentStateManager.computeMaxState());
    
        if (f.mState <= newState) {
            
            switch (f.mState) {
                ...
                case Fragment.CREATED:
                   
                    // 上次moveToState就止步于此
                    // 由于此时newState变为了STARTED,满足条件,因此Fragmet可以继续迁移状态了
                    if (newState > Fragment.CREATED) {
                        // 对于静态使用Fragment,这个方法没有做任何事,可以忽略
                        fragmentStateManager.createView(mContainer);
                        // 执行完毕后,Fragment的状态迁移为了ACTIVITY_CREATED,因此匹配到下一个case
                        fragmentStateManager.activityCreated();
                        fragmentStateManager.restoreViewState();
                    }
                    
                case Fragment.ACTIVITY_CREATED:
                    // newState为STARTED,满足条件,if语句执行
                    if (newState > Fragment.ACTIVITY_CREATED) {
                        // 方法执行完毕后,Fragment的状态迁移为了STARTED,因此匹配到下一个case
                        fragmentStateManager.start();
                    }
                    
                case Fragment.STARTED:
                    // 显然,newState不满足该条件,止步于此
                    if (newState > Fragment.STARTED) {
                        fragmentStateManager.resume();
                    }
            }
        } 
    	...
    }
复制代码

实际上有了onCreate阶段的讲解,这一次的moveToState(Fragment, int)过程就轻松多了。与上一次相比,Activity的生命周期变为了STARTED,那么Fragment的生命周期也可以迁移到这个上限STARTED。而onCeate阶段结束时,Fragment的状态为CREATED(onCreateView和onViewCreated没有定义对应的状态),在Fragment的生命周期中,CRAETED与STARTED中间还有一个ACTIVITY_CREATED,因此,本次moveToState(Fragment, int)就是使得Fragment完整这两步状态的迁移。

至此,Activity的onStart阶段状态转移过程就看完了,通过上面的代码我们知道了,在Activity的onStart阶段,Fragment依次执行了onActivityCreated、onStart两个生命周期回调

根据上面的讲解,我们可以得到如下调用流程示意:

Activity.onCreate -- begin
    
	Fragment.onAttach
	Fragment.onCreate
	Fragment.onCreateView
	Fragment.onViewCreated
    
Activity.onCreate -- end
Activity.onStart  -- begin
    
    Fragment.onActivityCreated
    Fragment.onStart
    
Activity.onStart  -- end
复制代码

此时的状态:

  • Activity(FragmentManager):STARTED;
  • Fragment:STARTED。

那么后续的生命周期调用该如何继续呢?

Activity — onResume

同样,onResume的方法传递过程稍微复杂一点,其入口是Activity的performResume:

// Activity.java
final void performResume(boolean followedByPause, String reason) {
        
        onPostResume();  
    }

// FragmentActivity.java
	protected void onPostResume() {
        super.onPostResume();
        onResumeFragments();
    }
    
    protected void onResumeFragments() {
        mFragmentLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME);
        mFragments.dispatchResume();
    }
复制代码

实际上,后面的过程就和onStart时一模一样了,这里就直接贴出moveToState的代码了:

// FragmentManager.java
// FragmentManager.java
void moveToState(@NonNull Fragment f, int newState) {
    	// 此时获取到的便不再是null了
        FragmentStateManager fragmentStateManager = mFragmentStore.getFragmentStateManager(f.mWho);
        // 结果是RESUMED
        newState = Math.min(newState, fragmentStateManager.computeMaxState());
    
        if (f.mState <= newState) {
            switch (f.mState) {
                ...
                
                case Fragment.STARTED:
                    // 此时,newState满足该条件,不载止步于此执行if语句
                    if (newState > Fragment.STARTED) {
                        // 方法执行完毕后,Fragment状态迁移为RESUMED
                        fragmentStateManager.resume();
                    }
            }
        } 
    	...
    }
复制代码

至此,Activity的onStart阶段状态转移过程就看完了,通过上面的代码我们知道了,在Activity的onResume阶段,Fragment执行了onResume生命周期回调

根据上面的讲解,我们可以得到如下调用流程示意:

Activity.onCreate -- begin
    
	Fragment.onAttach
	Fragment.onCreate
	Fragment.onCreateView
	Fragment.onViewCreated
    
Activity.onCreate -- end
Activity.onStart  -- begin
    
    Fragment.onActivityCreated
    Fragment.onStart
    
Activity.onStart  -- end
Activity.onResume -- begin
    
    Fragment.onResume
    
Activity.onResume -- end
复制代码

此时的状态:

  • Activity(FragmentManager):RESUMED;
  • Fragment:RESUMED。

至此,静态使用Fragment时,Activity生命周期对Fragment的控制,就讲解完毕了。

小结

分析到这一步,我们做一个小结:

  • FragmentManager与Activity:FragmentManager就是Activity的一个辅助类,其状态与Activity的生命周期状态同步;Activity在其自己的生命周期回调中,向FragmentManager发起指令,之后FragmentManager对所管理的Fragment进行状态的迁移,具体做法是Activity在生命周期方法中调用FragmentManager的dispatchXX方法,将生命周期事项分发给每一个Fragment;
  • Fragment与View:上文中提到了,在layout文件中使用Fragment时,Fragment被解析出来时返回mView,这一点上Fragment的行为很像是一个View,Fragment像View的一面就是因为mView的存在;与View不同的是,Fragment具有自己的生命周期,该生命周期与Activity的生命周期绑定在一起。==有了这个特点,原本需要在Activity的生命周期方法中执行的操作,就可以放在Fragment中进行,这减轻了Activity的工作量==。
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享