Jetpack 之LifeCycle

image.png

Q:什么是LifeCycle

androidx.lifecycle 软件包提供了可用于构建生命周期感知型组件的类和接口,可执行操作来响应另一个组件(如 Activity 和 Fragment)的生命周期状态的变化。

Q: 请说说LifeCycle的好处?

(1)我们在Activity的onCreate()中初始化某些成员(比如MVP架构中的Presenter,或者AudioManager、MediaPlayer等),然后在onStop中对这些成员进行对应处理,在onDestroy中释放这些资源,最终会有太多的类似调用并且会导致 onCreate() 和 onDestroy() 方法变的非常臃肿。比如定位组件,在onCreate中定义,在onStart中启动,在onStop中停止,在onDestory中销毁;同样的,录音组件也将有这一系列的生命周期,如果一个Activity中包含了若干个这样的组件,则会在生命周期方法中放置大量的代码,这使得它们难以维护。

(2)无法保证组件会在 Activity 或 Fragment 停止之前启动。在我们需要执行长时间运行的操作(如 [onStart()]中的某种配置检查)时尤其如此。这可能会导致出现一种竞态条件,在这种条件下,[onStop()] 方法会在 [onStart()] 之前结束,这使得组件留存的时间比所需的时间要长。

class MyActivity extends AppCompatActivity {
    private MyLocationListener myLocationListener;

    public void onCreate(...) {
        myLocationListener = new MyLocationListener(this, location -> {
            // update UI
        });
    }

    @Override
    public void onStart() {
        super.onStart();
        Util.checkUserStatus(result -> {
            // 有可能onStop()执行完毕了,回调还没有得到执行
            if (result) {
                myLocationListener.start();
            }
        });
    }

    @Override
    public void onStop() {
        super.onStop();
        myLocationListener.stop();
    }
}

[androidx.lifecycle] 软件包提供的类和接口可帮助您以弹性和隔离的方式解决这些问题,它将生命周期的响应分发到各个观察者中去

Q: 说说LifeCycle相关组件所扮演的角色?

-LifecycleOwner: 提供了获取Lifecycle接口实现的方法。通过LifecycleOwner,将Lifecycle的实现和Activity等生命周期组件解耦。可以把LifecycleOwner理解为Lifecycle的“工厂”。

  • Lifecycle:是被观察者,用于存储有关组件(如 Activity 或 Fragment)的生命周期状态的信息,并允许其他对象观察此状态
  • LifecycleObserver:观察者,可以通过被LifecycleRegistry类通过 addObserver(LifecycleObserver o)方法注册,被注册后,LifecycleObserver便可以观察到LifecycleOwner对应的生命周期事件

以上三者的持有关系:

LifecycleOwner -> Lifecycle -> (n) LifecycleObserver

Lifecycle.Event:分派的生命周期事件。这些事件映射到 Activity 和 Fragment 中的回调事件。
Lifecycle.State:Lifecycle组件的当前状态。
LifecycleRegistry: 添加观察者,响应生命周期事件,负责转发生命周期

Q: State和组件(Activity/Fragment)生命周期的对应关系?

  • INITIALIZED:对应Activity已实例化但在onCreate之前的生命周期
  • DESTROYED:此后,LifyCycle不再分派生命周期事件。此状态在Activity.onDestroy()之前
  • CREATED:对应Activity的onCreate之后和onStop之前的生命周期
  • STARTED:对应Activity的onStart之后和onPause之前的生命周期
  • RESUMED:对应Activity的onResume

Q:Lifecycle是怎样感知生命周期的?
AppComponent实现了LifycycleOwer接口声明了mLifecycleRegistry对象,但是没有直接使用其进行生命周期的分发,而是被ReportFragment通过activity.getLifecycle()获取使用。

ActivityAppCompatActivity中添加了一个ReportFragment,其生命周期变化时,调用LifecycleRegistry.handleLifecycleEvent()方法通知LifecycleRegistry改变状态,LifecycleRegistry内部调用moveToState()改变状态,并调用每个LifecycleObserver.onStateChange()方法通知生命周期变化。


image.png

Q:ReportFragment是如何被添加到Activity中的呢?
ReportFragment可以通过两种方式添加到Activity中。

1.如果Activity继承自ComponentActivity(AppCompatActivity的间接父类),ComponentActivity的onCreate方法中会调用ReportFragment的injectIfNeededIn(Activity)静态方法完成注入。

protected void onCreate(@Nullable Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      ReportFragment.injectIfNeededIn(this);
  }

2.如果Activity没有继承自ComponentActivity,Lifecycle使用LifecycleDispatcher类完成ReportFragment的注入。

LifecycleDispatcher和ProcessLifecycleOwner使用相同的方式跟随进程初始化(后文会提到),LifecycleDispatcher在其静态方法init(Context)中,使用Application.registerActivityLifecycleCallbacks(ActivityLifecycleCallbacks)方法向Application中注册了Activity生命周期回调监听器。在监听器的onActivityCreated(Activity, Bundle)回调方法(Activity创建时回调)中,调用ReportFragment.injectIfNeededIn(Activity)方法将ReportFragment注入到Activity中。

Q:为什么不直接在SupportActivity的生命周期函数中给Lifecycle分发生命周期事件,而是要加一个Fragment呢?

因为不是所有的页面都继承AppCompatActivity,为了兼容非AppCompatActivity,所以封装一个同样具有生命周期的Fragment来给Lifecycle分发生命周期事件。

Q:那我们不继承新版本AppCompatActivity时,Lifecycle是如何通过ReportFragment来分发生命周期事件的呢?

除了ComponentActivity以外,还有两个地方使用到了ReportFragment:LifecycleDispatcher和ProcessLifecycleOwner

  • LifecycleDispatcher

LifecycleDispatcher是通过注册Application.registerActivityLifecycleCallbacks来监听Activity的生命周期回调的。

  • 在onActivityCreated()中添加ReportFragment,将Activity的生命周期交给ReportFragment去分发给LifecycleRegistry
  • 在onActivityStopped()以及onActivitySaveInstanceState()中,将Activity及其所有子Fragment的State置为CREATED
  • ProcessLifecycleOwner
  • ProcessLifecycleOwner是用来监听Application生命周期的,因此它只会分发一次ON_CREATE事件,并且不会分发ON_DESTROY事件
  • ProcessLifecycleOwner在Activity的onPause和onStop方法中都采用了Handle.postDelayed()方法,是为了处理Activity重建时比如横竖屏幕切换时,不会发送事件。
  • ProcessLifecycleOwner一般用来判断应用是在前台还是后台。但由于使用了Handle.postDelayed(),因此这个判断不是即时的,有默认700ms的延迟。
  • ProcessLifecycleOwner与LifecycleDispatcher一样,都是通过注册Application.registerActivityLifecycleCallbacks来监听Activity的生命周期回调,来给每个Activity添加ReportFragment的。

Q: ProcessLifecycleOwner和LifecycleDispatcher两个类是在哪里初始化呢?

从源码中我们看到,Lifecycle自动在我们的AndroidManifest.xml中添加了一个ContentProvider,用于初始化ProcessLifecycleOwner和LifecycleDispatcher,这么做的好处是,不需要我们在Application中显示调用,不需要我们写一行代码。

Q:为什么LifecycleRegistry不是直接分发Event而是先计算State,再反推Event进行分发呢?

LifecycleRegistry的实现充分考虑了各种情况下事件分发的准确性,主要有两类问题:1. 可重入,2. 一致性。
这里的两次转换主要为了解决第2个问题,为了保证不同生命周期添加的观察者都能正确收到状态变换时的各种事件(一致性),不会漏掉,LifecycleRegistry通过两次转换实现了重放。

Q: FastSafeIterableMap的特性?

  • Map,K-V结构存储。
  • 有序,插入顺序决定保存顺序。支持正向、反向遍历。
  • 支持在遍历过程中添加、移除元素。(影响LifecycleRegistry的可重入性)
    LifecycleRegistry利用FastSafeIterableMap有序的特性,保证添加的Observer按照插入顺序,State从大到小的顺序排列。所以判断同步完成,只需要看第一个Observer和最后一个Observer的状态相等,并且等于LifecycleRegistry的状态。

Q: 如何保证FastSafeIterableMap中存放的ObserverWithState对象的state状态总是先入的会比后入的大?

sync方法因为在提升状态时从前向后遍历,降低状态时从后向前遍历,所以一定能保证执行过程中的状态要求;在有新Observer添加的情况下,也可通过防止重入的方式保证在任何时刻mObserverMap中前面的Observer的状态,一定要大于等于后面的Observer的状态。

Q:LifeCycle怎么防止LifeCycleObserver的重入操作?

LifecycleRegistry在处理生命周期事件时,只要涉及到分发事件,都可能出现重入的场景。因为在事件处理方法中,可能添加新的Observer或者移除现有的Observer,对Observer集合的修改,就是修改了外部变量。

LifecycleRegistry通过parentState缓存嵌套调用情况下上层调用时的状态,来保证下层调用方法执行时,要同步到的目标状态,不会超过上层状态,甚至是当上层的Observer已经被移除的情况(如果没有parentState缓存,后添加的Observer的状态就可能比先添加的Observer的状态更早同步到目标状态)。

这里的状态反映到调用者,更多体现在回调方法的调用顺序上。以onStart方法为例,先添加的Observer(A)的onStart方法,一定比后添加的Observer(B)的onStart方法先执行完成。即便是B在A的onStart方法中添加的情况下(A.onStart执行完成后,B.onStart方法才会执行)。

Q:LifeCycle使用了哪些设计模式

观察者模式:AppCompatActivity中添加了一个ReportFragment,其生命周期变化时,调用LifecycleRegistry.handleLifecycleEvent()方法通知LifecycleRegistry改变状态,LifecycleRegistry内部调用moveToState()改变状态,并调用每个LifecycleObserver.onStateChange()方法通知生命周期变化。
适配器模式:在ObserverWithState 静态内部类中, 使用适配器模式对传入的Observer进行封装,通过Lifecycling转为统一的LifecycleEventObserver对象,并同时保存对应的mState状态。

Q:LifecycleRegistry 会将外部传入的所有 LifecycleObserver 根据 Lifecycling 包装成 LifecycleEventObserver 对象,这里先来解释下为什么需要进行这层包装?

1.LifecycleEventObserver 和 FullLifecycleObserver 都是继承于 LifecycleObserver 的接口,如果开发者自己实现的自定义 Observer 同时实现了这两个接口,那按道理来说 LifecycleRegistry 就必须在有事件触发的情况下同时回调这两个接口的所有方法

2.如果开发者自己实现的自定义 Observer 仅实现了 LifecycleEventObserver 和 FullLifecycleObserver 这两个接口当中的一个,那么也需要在有事件触发的情况下调用相应接口的对应方法

3.除了通过以上两个接口来实现回调外,Google 也提供了通过注解的方法来声明生命周期回调函数,此时就只能通过反射来进行回调

基于以上三点现状,如果在 LifecycleRegistry 中直接对外部传入的 Observer 来进行类型判断、接口回调、反射调用等一系列操作的话,那势必会使得 LifecycleRegistry 整个类非常的臃肿,所以 Lifecycling 的作用就是来将这一系列的逻辑给封装起来,仅仅开放一个 onStateChanged 方法即可让 LifecycleRegistry 完成整个事件分发,从而使得整个流程会更加清晰明了且职责分明。

Lifecycle源码分析

硬核讲解 Jetpack 之 LifeCycle 源码篇

Android-Lifecycle超能解析-生命周期的那些事儿

Jetpack和LifeCycle(三)

Lifecycle源码解析,让你一次学个够!

万物基于lifecycle

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,524评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,869评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,813评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,210评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,085评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,117评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,533评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,219评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,487评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,582评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,362评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,218评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,589评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,899评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,176评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,503评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,707评论 2 335

推荐阅读更多精彩内容