FyListen——生命周期监听器(设计原理之理解生命周期)

文章详细解析了FyListen作为生命周期监听器的核心原理,包括通过子Fragment对Activity和Fragment的生命周期监听,以及Java8接口的default特性。内容涉及Context的基础实现、获取Context的方法、Application的作用,以及Activity与Fragment的生命周期绑定机制。文章深入源码,阐述了Fragment如何随着Activity的生命周期变化进行状态转移,并介绍了如何通过AMS回调Activity的生命周期方法。此外,还讨论了Fragment与子Fragment的生命周期绑定,以及如何利用Java8的default接口特性进行外观设计。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

FyListen——生命周期监听器(设计原理之理解生命周期)

FyListen 的核心原理有两个:

  1. 通过子Fragment对Activity、Fragment进行生命周期监听
  2. 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状态转移图:(图来自稀土掘金)

img

这张图的解读可以看到下面这张表,Activity 管理 Fragment 生命周期的方式是在 Activity 的生命周期方法中调用 FragmentManager 的对应方法,通过 FragmentManager 将现有的 Fragment 迁移到下一个状态,同时触发相应的生命周期函数:

Activity生命周期函数FragmentManager触发的方法Fragmet你状态转移Fragment生命周期回调
onCreate()dispatchCreateINITIALIZING->CREATEDonAttach()、onCreate()
dispatchActivityCreated()CREATED->ACTIVITY_CREATEDonCreateView()、onActivityCreated()、
onStart()dispatchStartACTIVITY_CREATED->STARTEDonStart()
onResume()dispatchResumeSTARTED->RESUMEDonResume()
onPausedispatchPauseRESUMED->STARTEDonPause()
onStopdispatchStopSTARTED->STOPPEDonStop()
onDestroydispatchDestroySTOPPED->ACTIVITY_CREATED->CREATED->CREATED->INITIALIZINGonDestroyView()、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当前状态还在INITIALIZINGActivity调用了onCreate(),newState是CREATEDFragment进行状态转移
                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()

  1. 在 Activity 的 onCreate() 中将 Fragment 的状态转移目标 newState 设置为了 CREATED,状态转移期间回调了Fragment的 onAttach() 和 onCreate()
  2. 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()

  1. 调用了 Activity 的 onStart()
  2. 将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()

  1. 调用了 Activity 的 onResume()
  2. 将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的生命周期回调

  1. 注意,状态转移设为newState=STARTED,开始往回转移!!!
  2. Fragment状态转移期间回调了onPause()方法
  3. 然后才调用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的生命周期回调

  1. 注意,状态转移目标设为newState = STOPPED,往回状态转移
  2. Fragment状态转移期间回调了 onStop()方法
  3. 然后才调用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的生命周期回调

  1. 先进行Fragment状态转移,newState=INITIALIZING,期间回调了Fragment的onDestroyView,onDestroy,onDetach
  2. 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 的调度时候回调生命周期:

先来看这张图:(图源稀土掘金)

img

我们经常使用 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
使得可以往接口里添加默认方法,子类可以无需变动。

同时,这也使得接口中的方法并不需要全都实现,只需要重写需要的方法即可!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值