FyListen——生命周期监听器(设计原理之理解生命周期)
FyListen 的核心原理有两个:
- 通过子Fragment对Activity、Fragment进行生命周期监听
- Java8 接口特性 default
1. 什么是上下文Context
这是一个装饰器模式, ContextImpl 是 Context 的基础实现类, ContextWrapper 是对 ContextImpl 的包装类。ContextThemeWrapper 是对装饰器的再装饰,又增加了一些功能。
1.1 如何获取 Context?
获取 Context 的方法有很多:getContext(), getBaseContext(), getApplication(), getApplicationContext()。我们来看一下他们的区别:
getApplication()和 getApplicationContext() 获取到的就是同一个对象,只是使用的范围不一样:
- getApplication() 只有 Activity 和 Service 才有。
- 想要在其他地方获取 Application 只能通过 getApplicationContext().
getContext(), getBaseContext()和 getApplicationContext() 有什么区别?
-
Activity,Service 和 Application 都有 getBaseContext(),getApplicationContext() 这两个方法,但没有 getContext() 方法。
-
getContext() 方法只有在 Fragment 中才有,获取的是寄主对象,也就是 Activity。
所以 Fragment 必须依赖于 Activity 存在
1.2 Application 有什么用?
Application 是全局单例,可以通过 getApplication() 和 getApplicationContext() 获取。
需要注意的是,如果在 application 中调用 context 的方法,必须在 attachBaseContext() 之后,在此之前 context 是没有赋值的。
2. Activity 与 Fragment 生命周期绑定原理
先来看一张Fragment状态转移图:(图来自稀土掘金)
这张图的解读可以看到下面这张表,Activity 管理 Fragment 生命周期的方式是在 Activity 的生命周期方法中调用 FragmentManager 的对应方法,通过 FragmentManager 将现有的 Fragment 迁移到下一个状态,同时触发相应的生命周期函数:
Activity生命周期函数 | FragmentManager触发的方法 | Fragmet你状态转移 | Fragment生命周期回调 |
---|---|---|---|
onCreate() | dispatchCreate | INITIALIZING->CREATED | onAttach()、onCreate() |
dispatchActivityCreated() | CREATED->ACTIVITY_CREATED | onCreateView()、onActivityCreated()、 | |
onStart() | dispatchStart | ACTIVITY_CREATED->STARTED | onStart() |
onResume() | dispatchResume | STARTED->RESUMED | onResume() |
onPause | dispatchPause | RESUMED->STARTED | onPause() |
onStop | dispatchStop | STARTED->STOPPED | onStop() |
onDestroy | dispatchDestroy | STOPPED->ACTIVITY_CREATED->CREATED->CREATED->INITIALIZING | onDestroyView()、onDestroy()、onDetach() |
我们从源码角度来看一下是如何绑定的生命周期,首先我们需要知道,Activity 生命周期是由 AMS(ActivityManagerService)管理、回调的,这部分请大家在 AMS 专题学习。便于理解,我们提前看到源码中关于Fragment的状态转移代码处理:
需要提醒的Java基础是,switch: 一旦switch表达式与某个case分支匹配,则从该分支的语句开始执行,一致执行下去!其后所有case分支的语句也会被执行,直到遇到break语句!!!
//[FragmentManager.java]
void moveToState(Fragment f, int newState, int transit, int transitionStyle,boolean keepActive) {
//newState是Fragment将要被转移到的状态state
//f.mState是Fragment现有的状态state
if(f.mState <= newState){
switch(f.mState){
case Fragment.INITIALIZING://Fragment当前状态还在INITIALIZING,Activity调用了onCreate(),newState是CREATED,Fragment进行状态转移
if(newState > Fragment.INITIALIZING){
f.onAttach();
dispatchOnFragmentAttached();
if(!f.mIsCreated){
//如果fragment还没create()
f.performCreate();
dispatchOnFragmentCreated();
}else{
//如果fragment过去已经create()过了,只不过是detach()了,并没有销毁。也就是这个Fragment虽然生命结束了,但后来又被加载使用了(复用了)
f.mState = Fragment.CREATED;
}
}
case Fragment.CREATED:
if(newState > Fragment.CREATED){//Fragment当前状态在CREATED,但Activity紧接着又将状态调整为ACTIVITY_CREATED,Fragment进行状态转移
f.mView = f.performCreateView();
if(f.mView!=null){
//如果没有view,就不往它的子Fragment进行生命周期回调分发了
dispatchOnFragmentViewCreated();
}
f.performActivityCreated();
dispatchOnFragmentActivityCreated();
}
case Fragment.ACTIVITY_CREATED:
if(newState > Fragment.ACTIVITY_CREATED){
//只进行状态转移
f.mState = Fragment.STOPPED;
}
case Fragment.STOPPED:
if(newState > Fragment.STOPPED){
f.performStart();
dispatchOnFragmentStarted();
}
case Fragment.STARTED:
if(newState > Fragment.STARTED){
f.performResume();
dispatchOnFragmentResumed();
}
}
}else if(f.mState > newState){
//反向转移
switch(f.mState){
case Fragment.RESUMED:
if(newState < Fragment.RESUMED){
f.performPause();
dispatchOnFragmentPaused();
}
case Fragment.STARTED:
if(newState < Fragment.STARTED){
f.performStop();
dispatchOnFragmentStopped();
}
case Fragment.STOPPED:
case Fragment.ACTIVITY_CREATED:
if(newState < Fragment.ACTIVITY_CREATED){
f.performDestroyView();
dispatchOnFragmentViewDestroyed();
}
case Fragment.CREATED:
if(newState < Fragment.CREATED){
f.performDestroy();
dispatchOnFragmentDestroy();
}
f.performDetach();
dispatchOnFragmentDetached();
}
if(f.mState != newState){
f.mState = newState;
}
}
}
我们了解了 Fragment 的生命周期是由于 Activity 生命周期的回调,设定了 Fragment 应当到的 newState,然后让 Fragment 进行状态转移,转移的过程中回调 Fragment 的生命周期。所以我们主要需要看 Activity 是如何设置 newState 的。从 AMS 回调 Activity 的 performXXX() 看起:
2.1 AMS->Activity.performCreate()
- 在 Activity 的 onCreate() 中将 Fragment 的状态转移目标 newState 设置为了 CREATED,状态转移期间回调了Fragment的 onAttach() 和 onCreate()
- performCreate()又将 Fragment 的状态转移目标newState设置为了 ACTIVITY_CREATED,Fragment在状态转移期间回调了Fragment的 onCreateView() 和 onActivityCreate()
//[Activity.java]
final void performCreate(Bundle icicle, PersistableBundle persistentState) {
//调用Activity的onCreate()方法,其中回调了Fragment的onAttach()和onCreate()方法
if (persistentState != null) {
onCreate(icicle, persistentState);
} else {
onCreate(icicle);
}
//调用到moveToState,且newState为Fragment.ACTIVITY_CREATED,状态转移过程中,回调了Fragment的onCreateView()和onActivityCreate().
mFragments.dispatchActivityCreated();
}
protected void onCreate(@Nullable Bundle savedInstanceState) {
//调用到moveToState,且newState为Fragment.CREATED,在状态转移期间回调了Fragment的onAttach()和onCreate()方法
mFragments.dispatchCreate();
//Application的Lifecycle回调
dispatchActivityCreated(savedInstanceState);
}
2.2 AMS->performStart()
- 调用了 Activity 的 onStart()
- 将Fragment的状态转移目标newState设置为了STARTED,Fragment在期间回调了Fragment的 onStart() 方法
//[Activity.java]
final void performStart(String reason){
//回调了 activity.onStart(),其中进行Application的Lifecycle回调
mInstrumentation.callActivityOnStart(this);
//调用到moveToState,且newState为Fragment.STARTED,其中回调了onStart()方法。虽然在switch中将Fragment的状态停留在了STOPPED,但在moveToState()方法的最后,又将Fragment的状态设置到了STARTED。
mFragments.dispatchStart()
}
2.3 AMS->performResume()
- 调用了 Activity 的 onResume()
- 将Fragment的状态转移目标newState设置为了RESUMED,Fragment在状态转移期间回调了Fragment的 onResume();
//[Activity.java]
final void performResume(boolean followedByPause, String reason){
//如果activity之前不是started的,会进入此方法,确保将activity变为start
performRestart(true,reason);
//如果activity之前是start的:
//回调activity.onResume(),里面回调了 Application的Lifecycle
mInstrumentation.callActivityOnResume(this);
//调用到moveToState,且newState为Fragment.RESUMED,状态转移期间回调了Fragment的onResume()方法
mFragments.dispatchResume();
}
2.4 AMS->performPause()
【注意!!!】我们发现,从这里开始,是先从Fragment开始状态转换,而且是往回转移,newState<f.mState,然后才调用Activity的生命周期回调
- 注意,状态转移设为newState=STARTED,开始往回转移!!!
- Fragment状态转移期间回调了onPause()方法
- 然后才调用Activity的onPause()方法
//[Activity.java]
final void performPause(boolean preserveWindow, String reason) {
//在此之前状态为RESUMED,由于f.mState<newState,将进行往回状态转移!
//Fragment状态转移到STARTED期间回调了Fragment的onPause()
mFragments.dispatchPause();
//调用Activity的onPause(),同时回调Application的Lifecycle
onPause();
}
2.5 AMS->performStop()
【注意!!!】先从Fragment开始状态转换,而且是往回转移,newState<f.mState,然后才调用Activity的生命周期回调
- 注意,状态转移目标设为newState = STOPPED,往回状态转移
- Fragment状态转移期间回调了 onStop()方法
- 然后才调用Activity的onStop()方法
//[Activity.java]
final void performStop(boolean preserveWindow, String reason) {
//Fragment状态转移到STOPPED,往回状态转移期间,回调了Fragment的onStop()方法
mFragments.dispatchStop();
//其中回调了Activity的onStop(),同时回调Application中的监听Lifecycle
mInstrumentation.callActivityOnStop(this);
}
2.6 AMS->performRestart()
Activity可能会在onStop()之后又onRestart(),需要注意的是,这里并没有回调Fragment的生命周期,只调用了activity的onRestart(),并调用performStart(),后续的生命周期回调就和onStart()之后的一致了
//[Activity.java]
final void performRestart(boolean start, String reason) {
//先判断之前是否为Stop状态
if(mStopped){
mStopped = false;
//调用Activity的onRestart()回调
mInstrumentation.callActivityOnRestart(this);
//里面调用了Activity的onStart(),并进行Fragment状态转移与生命周期回调
performStart();
}
}
final void performStart(String reason) {
//调用Activity.onStart(),并回调Application的Lifecycle,通知Application这个activity的生命周期现状
mInstrumentation.callActivityOnStart(this);
//newState=STARTED,Fragment状态从STOPPED到STARTED状态转移,期间回调了Fragment的onStart()
mFragments.dispatchStart();
}
2.7 AMS->performDestroy()
【注意!!!】先从Fragment开始状态转换,而且是往回转移,newState<f.mState,然后才调用Activity的生命周期回调
- 先进行Fragment状态转移,newState=INITIALIZING,期间回调了Fragment的onDestroyView,onDestroy,onDetach
- Fragment状态转移完成,才进行Activity的onDestroy()
//[Activity.java]
final void performDestroy(){
//先进行Fragment状态转移,newState=INITIALIZING,期间回调了Fragment的onDestroyView,onDestroy,onDetach
mFragments.dispatchDestroy();
//Fragment状态转移完成,才进行Activity的onDestroy()
onDestroy();
}
我们回到 moveToState 来看一下是怎么连着回调三个Fragment生命周期的,需要注意,此时f.mState = STOPPED,newState=INITIALIZING:
需要提醒的Java基础是,switch: 一旦switch表达式与某个case分支匹配,则从该分支的语句开始执行,一致执行下去!其后所有case分支的语句也会被执行,直到遇到break语句!!!
//[FragmentManager.java]
void moveToState(Fragment f, int newState, int transit, int transitionStyle,boolean keepActive) {
if(f.mState 《= newState){
//...
}else if(f.mState > newState){
switch(f.mState){
//...
case Fragment.STOPPED://分支判断成功,继续执行后续case分支语句,直到遇到break
case Fragment.ACTIVITY_CREATE:
if(newState < Fragment.ACTIVITY_CREATED){
//1. 回调Fragment的onDestroyView()
f.performDestroyView();
//把该事件也分发给f的子Fragment
dispatchOnFragmentViewDestroyed();
}
case Fragment.CREATED:
if(newState < Fragment.ACTIVITY_CREATED){
//2. 回调Fragment的onDestroy()
f.performDestroy();
//把该事件也分发给f的子Fragment
dispatchOnFragmentDestroyed();
//3. 回调Fragment的onDetach()
f.performDetach();
//把该事件也分发给f的子Fragment
dispatchOnFragmentDetached();
}
//switch end
}
}
//状态转移完成,最终更新f.mState = INITIALIZING
if(f.mState != newState){
f.mState = newState;
}
}
至此,我们分析完了生命周期回调。如果你比较细心,会发现这里除了处理fragment的生命周期,还有的时候会处理fragment的动画和view的显示。
2. 补充:Fragment生命周期除了自动由 Activity 来回调,也可以由用户操控 FragmentTansaction 进行 Fragment 的调度时候回调生命周期:
先来看这张图:(图源稀土掘金)
我们经常使用 FragmentTransaction 中的 add()、remove()、replace()、attach()、detach()、hide()、show() 等方法对 Fragment进行操作,这些方法都会使 Fragment 的状态发生变化,出发对应的生命周期函数。默认 Activity 处于 Resume 状态:
- add/remove 操作会引起 Fragment 在 INITIALIZING 和 RESUMED 这两个状态之间迁移
- attach/detach操作会引起 Fragment 在 CREATED 和 RESUMED 两个状态之间迁移
add() 需要注意的是,如果Activity处于 STARTED 状态,Fragment 是无法进入 RESUMED 状态的,只有当 Activity 进入 RESUME 状态才会通知 Fragment 进入 RESUMED。
hide/show方法内部其实调用了 FragmentTransaction 的add/remove 方法。
3. Fragment 与 子Fragment 生命周期绑定原理
我们观察到 Fragment 中也持有一个 FragmentManager:mChildFragmentManage 用于管理子Fragment。所以在生命周期事件分发过程中,会呈树形结构向所有子Fragment进行分发:
//[Fragment.java]
public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListener {
//上层管理当前Fragment的FragmentManager
FragmentManagerImpl mFragmentManager;
//当前Fragment用于管理子Fragment的fm,在生命周期回调中,会同时分发给 MChildFragmentManager 中的所有子Fragment
FragmentManagerImpl mChildFragmentManager;
//所属的父Fragment
Fragment mParentFragment;
}
FragmentManager 中管理着 Fragments:mAdds 和 mActive:
//[FragmentManager.java]
final class FragmentManagerImpl extends FragmentManager implements LayoutInflater.Factory2 {
//当前活跃的Fragment
SparseArray<Fragment> mActive;
//所有已添加的Fragment
final ArrayList<Fragment> mAdded = new ArrayList<>();
//管理的其他信息
ArrayList<BackStackRecord> mBackStack;
ArrayList<Fragment> mCreatedMenus;
//...
//分发生命周期:以dispatchResume()为例
public void dispatchResume(){
mStateSaved = false;
//进行Fragment的状态转移
dispatchMoveToState(Fragment.RESUMED);
}
//其中通过moveToState先进行预处理,即找到所有当前FragmentManager所管理的Fragment进行逐个事件分发
private void dispatchMoveToState(int state) {
if (mAllowOldReentrantBehavior) {
moveToState(state, false);
} else {
try {
mExecutingActions = true;
moveToState(state, false);
} finally {
mExecutingActions = false;
}
}
execPendingActions();
}
//拿到 mAdds 和 mActive 中的Fragment去分发事件(逐个让他们去进行状态转移)
//注意这个是两个参数的 moveToState(),真正状态转移的moveToState()方法是四个参数的,注意区分
void moveToState(int newState,boolean always){
if (mActive != null) {
final int numAdded = mAdded.size();
for (int i = 0; i < numAdded; i++) {
Fragment f = mAdded.get(i);
//逐个fragment进行状态转移
moveFragmentToExpectedState(f);
}
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) {
//逐个fragment进行状态转移
moveFragmentToExpectedState(f);
}
}
}
}
//moveFragmentToExceptedState()通过四个参数的moveToState()让fragment进行状态转移
void moveFragmentToExceptedState(final Fragment f){
int nextState = mCurState;//新状态被标记在成员变量,不作为参数传入,简化代码
//进行状态转移,具体的我们之前已经看过了
moveToState(f, nextState, f.getNextTransition(), f.getNextTransitionStyle(), false);
}
}
4. Activity与Fragment的树形结构
既然我们已经知道了 Fragment 的生命周期可以由 Activity 或者 Fragment 进行回调,那么我们就可以通过这个特性进行 Activity 或者 父Fragment生命周期的监听!!!主流框架 Glide 中生命周期监听的方式,也是利用了这个特性。我画了两张图,大家先感性地认知一下 Fragment 监听 Activity 生命周期的构造:
Activity与Fragment的树形结构:
我们可以看到,这是一个可以找到父节点的多叉树。
fragment想要与Activity通信可以通过Fragment中的 FragmentHostCallback类型对象mHost:里面存了Fragment所依存的Activity实例、主线程Handler。Fragment中启动Activity,也是通过这个对象,让上层去执行启动Activity的请求。
5. 使用 Java8 接口特性 default 进行外观设计
java8 之前,往接口里新加一个方法,那么所有的实现类都需要变动,都需要同步实现这个方法。
java8 给接口新增了两个关键字:default static
使得可以往接口里添加默认方法,子类可以无需变动。
同时,这也使得接口中的方法并不需要全都实现,只需要重写需要的方法即可!