Jetpack Lifecycle 该怎么看?还肝否?

前言

Jetpack AAC 系列文章:

Jetpack Lifecycle 该怎么看?还肝否?
Jetpack LiveData 是时候了解一下了
Jetpack ViewModel 抽丝剥茧

前面几篇文章都是为了Jetpack 打基础,本篇从Lifecycle开始将正式进入Jetpack 各个组件的分析。
通过本篇文章你将了解到:

1、为什么需要Lifecycle?
2、Lifecycle 如何使用?
3、Lifecycle 如何感知生命周期
4、Lifecycle 内存泄漏?
5、总结

1、为什么需要Lifecycle?

生命周期的起始

Android 中常见的拥有生命周期的组件如Activity、Fragment、Service等,其中Activity、Fragment最为常见,而Fragment的生命周期依托于Activity,因此掌握了Activity的生命周期,其它不在话下。
Activity 生命周期跌宕起伏的故事,请移步:
Android Activity 生命周期详解及监听

生命周期的运用

青铜选手

举个简单的例子:当进入Activity 时(获取焦点)需要网络请求,当Activity 退出时(失去焦点)停止网络请求,最简单的做法如下:

    @Override
    protected void onResume() {
        super.onResume();
        NetRequest.startRequest();
    }

    @Override
    protected void onPause() {
        super.onPause();
        NetRequest.stopRequest();
    }

重写onResume()方法,当该方法被调用时,说明Activity获取了焦点,页面即将展示,此时可以进行网络请求拉取数据。
重写onPause()方法,当该方法被调用时,说明Activity 失去了焦点,此时没必要再请求网络了。
看似没啥问题,但仔细想想:比如在播放视频的时候,也需要在onResume()方法里播放,在onPause()方法里暂停,再比如数据库操作等,这个时候onResume()、onPause()里就叠放了许多代码,使得Activity 变得很臃肿。

白银选手

你说没关系,我有MVP 架构,可以用Presenter 来封装这些业务逻辑。
声明Presenter类:LifecyclePresenter

public class LifecyclePresenter implements ILifecycle{
    @Override
    public void onResume() {
        NetRequest.startRequest();
    }

    @Override
    public void onPause() {
        NetRequest.stopRequest();
    }
}

该类实现了接口:ILifecycle,而此接口声明的方法与Activity 生命周期契合:

interface ILifecycle {
    void onCreate();
    void onStart();
    void onResume();
    void onPause();
    void onStop();
    void onDestroy();
}

好了,最后在Activity 里监听生命周期的变化,进而调用LifecyclePresenter 不同方法:

    @Override
    protected void onResume() {
        super.onResume();
        lifecyclePresenter.onResume();
    }

    @Override
    protected void onPause() {
        super.onPause();
        lifecyclePresenter.onPause();
    }

如此一来,以后有其它的业务逻辑,只需要在LifecyclePresenter 对应的方法里添加即可,达成了给Activity 减负的效果。

黄金选手

虽然Activity 生命周期各个方法里只新增了一行代码,但是考虑到UI 和逻辑的分离,最好是两者不产生耦合。比如在分工的时候,有些同学负责UI,那么他可能就不会关心什么时候开始/结束网络请求,这些由负责具体业务逻辑的同学来编写。该怎么来实现呢?
还记得在分析Activity生命周期时有说过:
Activity 提供了registerActivityLifecycleCallbacks(callback)方法,当Activity生命周期发生变动时就会调用该方法。因此咱们可以在此监听生命周期的变动,然后调用相应的业务代码:

public class LifecycleHelper {
    @RequiresApi(api = Build.VERSION_CODES.Q)
    public static void bindLifecycle(Activity activity, ILifecycle iLifecycle) {
        if (activity == null)
            return;
        activity.registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() {
            @Override
            public void onActivityResumed(@NonNull Activity activity) {
                if (iLifecycle != null)
                    iLifecycle.onResume();
            }

            @Override
            public void onActivityPaused(@NonNull Activity activity) {
                if (iLifecycle != null)
                    iLifecycle.onPause();
            }
        });
    }
}

传入的Activity 即为想要监听生命周期的Activity。

public class LifecyclePresenterV2 {
    @RequiresApi(api = Build.VERSION_CODES.Q)
    public LifecyclePresenterV2(Activity activity) {
        LifecycleHelper.bindLifecycle(activity, new ILifecycle() {
            @Override
            public void onResume() {
                NetRequest.startRequest();
            }

            @Override
            public void onPause() {
                NetRequest.stopRequest();
            }
        });
    }
}

改造Presenter为:LifecyclePresenterV2。
此时,Activity 里只需要调用:

  //this 表示当前需要监听的Activity
  LifecyclePresenterV2 lifecyclePresenterV2 = new LifecyclePresenterV2(this);

可以看出:

Activity 里无需再重写各个生命周期的回调方法,仅仅只需要一行代码,即可将这些逻辑放到单独的业务层处理,生命周期和具体业务绑定,看业务的需求想怎么和生命周期联动就怎么来。
后续若是换了Activity,那么逻辑层的业务也无需变动。

似乎万事大吉了?非也,仔细看registerActivityLifecycleCallbacks()方法调用有版本限制:@RequiresApi(api = Build.VERSION_CODES.Q)
意思就是该API 必须是Android 10(29)以上才能调用,这局限性可大了。

Lifecycle 的引入

从上面的分析我们可以感知到,生命周期和业务的联动场景挺丰富的,也着实需要一套工具来帮助我们简化联动过程。

Google说要有Lifecycle,于是便有了Lifecycle。

开宗明义:Lifecycle 源码并不复杂,主要就是做了三件事:

1、提供给外界监听感兴趣的生命周期里的某个阶段(onResume、onPause、onDestroy等)的接口,外界此时化身为观察者。
2、在某个地方监听Activity生命周期,此时Activity为被观察者。
3、将生命周期告知给观察者。

2、Lifecycle 如何使用?

添加观察者

从Lifecycle 三件事可知,外界想要监听生命周期变化,仅仅只需要添加观察接口,在接口的回调方法里处理对应生命周期即可。
有两种不同的方式:

1、注解方式处理观察结果

Lifecycle 以前的版本为了少重写接口里的方法,使用了注解来简化观察者。

    //注解的实现方式
    class MyObserver7 implements LifecycleObserver {
        @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
        void onPause() {
            Log.d(TAG, "onPause");
        }
    }

此处只关注onPause,若是还想监测其它状态变化,只需要添加对应状态的注解即可。
而后在Activity 里监听:

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_lifecycle);

        getLifecycle().addObserver(new MyObserver7());
    }

当Activity 失去焦点后就会调用MyObserver7里的onPause()方法。
可以看出,在Activity里只需要添加观察者即可。

2、接口方式处理观察结果

Lifecycle 新版本废弃了注解观察方式,使用了接口来代替,若是你使用了Java8或者开启了Java8 特性,建议使用接口方式。

    //Java8 方式
    class MyObserver8 implements DefaultLifecycleObserver {
        @Override
        public void onPause(LifecycleOwner owner) {
            Log.d(TAG, "pause");
        }
    }

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_lifecycle);
        getLifecycle().addObserver(new MyObserver8());
    }

可以看出,实现了DefaultLifecycleObserver 接口,该接口继承了FullLifecycleObserver 接口。

interface FullLifecycleObserver extends LifecycleObserver {
    void onCreate(LifecycleOwner owner);
    void onStart(LifecycleOwner owner);
    void onResume(LifecycleOwner owner);
    void onPause(LifecycleOwner owner);
    void onStop(LifecycleOwner owner);
    void onDestroy(LifecycleOwner owner);
}

而DefaultLifecycleObserver 接口默认实现了FullLifecycleObserver全部的方法

    @Override
    default void onCreate(@NonNull LifecycleOwner owner) {
    }
    ....

可以看出使用了Java8 的新特性:default 修饰接口方法。
因此当我们实现了DefaultLifecycleObserver接口时,仅仅只需要重写关注的状态对应的接口即可。

3、Lifecycle 如何感知生命周期

综上所述,通过Lifecycle 可以很方便地感知Activity生命周期的变化,前面部分咱们也是一步步分析该怎么封装生命周期,很遗憾遇到了registerActivityLifecycleCallbacks 版本限制的问题,接下来探究Lifecycle究竟是怎么做到绕开限制的。

第一步:注册观察者

LifecycleRegistry

不管是接口还是注解方式都使用了getLifecycle(),该方法返回Lifecycle 对象,而Lifecycle是抽象类,getLifecycle()返回的是Lifecycle 的子类:LifecycleRegistry 的对象。

#ComponentActivity.java
    private LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);
    public Lifecycle getLifecycle() {
        return mLifecycleRegistry;
    }

当自定义的Activity 继承自AppCompatActivity时,而ComponentActivity 是AppCompatActivity 的父类,因此自定义的Activity 调用getLifecycle()时返回的即是mLifecycleRegistry 对象。
而LifecycleRegistry里的mLifecycleOwner对象即是自定义的Activity 本身(弱引用)。

addObserver()

#LifecycleRegistry.java
    @Override
    public void addObserver(@NonNull LifecycleObserver observer) {
        Lifecycle.State initialState = mState == DESTROYED ? DESTROYED : INITIALIZED;
        //传入observer,构造ObserverWithState
        LifecycleRegistry.ObserverWithState statefulObserver = new LifecycleRegistry.ObserverWithState(observer, initialState);
        //将ObserverWithState 加入到map 里
        LifecycleRegistry.ObserverWithState previous = mObserverMap.putIfAbsent(observer, statefulObserver);
        ...
    }

关键之处在于ObserverWithState:

#LifecycleRegistry.java
    static class ObserverWithState {
        //生命周期状态
        Lifecycle.State mState;
        //观察者
        LifecycleEventObserver mLifecycleObserver;

        ObserverWithState(LifecycleObserver observer, Lifecycle.State initialState) {
            //封装观察者
            mLifecycleObserver = Lifecycling.lifecycleEventObserver(observer);
            mState = initialState;
        }

        void dispatchEvent(LifecycleOwner owner, Lifecycle.Event event) {
            //分发事件,将event转为state
            Lifecycle.State newState = event.getTargetState();
            mState = min(mState, newState);
            mLifecycleObserver.onStateChanged(owner, event);
            mState = newState;
        }
    }

再看Lifecycling.lifecycleEventObserver:

#Lifecycling.java
    static LifecycleEventObserver lifecycleEventObserver(Object object) {
        //接口方式
        boolean isFullLifecycleObserver = object instanceof FullLifecycleObserver;
        ...
        if (isFullLifecycleObserver) {
            //如果观察者是接口方式,直接返回
            return new FullLifecycleObserverAdapter((FullLifecycleObserver) object, null);
        }

        //处理注解,将注解记录下来,下次直接从map里取
        final Class<?> klass = object.getClass();
        int type = getObserverConstructorType(klass);
        ...
        return new ReflectiveGenericLifecycleObserver(object);
    }

addObserver()的重点是将Observer经过一些列封装后添加到Map里。

明显地我们会想到:当生命周期变更后,将会从Map里取出观察者,并通知它。

第二步:生命周期变更-通知观察者

Android10(含) 以上处理方式

了解Lifecycle 如何通知观察者,最好的方法莫过于通过断点查看其调用堆栈。
以接口处理方式为例,当观察者被调用时,其调用栈如下:


image.png

注意到Activity. dispatchActivityPostStarted()方法:

#Activity.java
    private void dispatchActivityPostStarted() {
        //找到监听者
        Object[] callbacks = collectActivityLifecycleCallbacks();
        if (callbacks != null) {
            for (int i = 0; i < callbacks.length; i++) {
                //调用回调方法
                ((Application.ActivityLifecycleCallbacks) callbacks[i])
                        .onActivityPostStarted(this);
            }
        }
        ...
    }

而此处的监听者即为通过Activity.registerActivityLifecycleCallbacks(callback)注册的。
而callback 即为:ReportFragment.LifecycleCallbacks 对象,该对象的注册在:

#ReportFragment.java
    public static void injectIfNeededIn(Activity activity) {
        if (Build.VERSION.SDK_INT >= 29) {
            //如果是Android10以上,则直接注册ActivityLifecycleCallbacks
            ReportFragment.LifecycleCallbacks.registerIn(activity);
        }
        //将一个空的Fragment添加到Activity里
        android.app.FragmentManager manager = activity.getFragmentManager();
        if (manager.findFragmentByTag(REPORT_FRAGMENT_TAG) == null) {
            manager.beginTransaction().add(new ReportFragment(), REPORT_FRAGMENT_TAG).commit();
            // Hopefully, we are the first to make a transaction.
            manager.executePendingTransactions();
        }
    }

而injectIfNeededIn的调用时机是在Activity.onCreate()里。
好了,现在我们已经了解了:

在Activity 创建时,通过ReportFragment 监听Activity 状态变化。

而ReportFragment 依据系统版本的不同,分两种监听方式:

1、在Android 10以上(含)的设备是通过registerActivityLifecycleCallbacks()监听的。
2、在Android 10以下是通过Fragment 监听的。

行文至此,Lifecycle仅仅只是监听了Activity 的状态,还需要将状态分发下去。
还是以Android10处理方式为例:

#ReportFragment.java
    static void dispatch(@NonNull Activity activity, @NonNull Lifecycle.Event event) {
        ...
        if (activity instanceof LifecycleOwner) {
            //获取Lifecycle,也即是LifecycleRegistry
            Lifecycle lifecycle = ((LifecycleOwner) activity).getLifecycle();
            if (lifecycle instanceof LifecycleRegistry) {
                //分发事件
                ((LifecycleRegistry) lifecycle).handleLifecycleEvent(event);
            }
        }
    }

最终事件还是交由LifecycleRegistry 处理,而LifecycleRegistry 里依据Event和State 转换,最后从Map 里找到对应的封装Observer,最终通知Activity里注册的observer,至此就完成了一次生命周期状态变化的通知。

Android 10以下处理方式

我们知道,当Fragment关联上Activity时,那么它的生命周期就与Activity 联动了。具体请移步:Android Fragment 要你何用?

因此当Activity 生命周期变化时,会调用Fragment某个方法,以onStart()状态为例:

#ReportFragment.java
    @Override
    public void onStart() {
        super.onStart();
        dispatchStart(mProcessListener);
        //分发事件
        dispatch(Lifecycle.Event.ON_START);
    }

    private void dispatch(@NonNull Lifecycle.Event event) {
        if (Build.VERSION.SDK_INT < 29) {
            //Android 10 以下才处理
            dispatch(getActivity(), event);
        }
    }

此时,我们知道了Lifecycle 如何处理registerActivityLifecycleCallbacks()版本限制问题:即是通过ReportFragment 对上层调用者屏蔽监听Activity生命周期变化的细节。在Android 10(含)以上使用registerActivityLifecycleCallbacks(),在其之下使用空的Fragment 添加到Activity。

Lifecycle 感知生命周期总结

用图表示如下:


image.png

绿色部分:

Lifecycle 监听Activity生命周期变化。

蓝色部分:

外界通过Lifecycle 注册观察者。

红色部分:

Lifecycle 监听到生命周期发生变化,通知观察者。

4、Lifecycle 内存泄漏?

在Activity(假设自定义为LifeActivity) onCreate()里添加如下代码,监测Activity 生命周期:

        getLifecycle().addObserver(new DefaultLifecycleObserver() {
            @Override
            public void onCreate(@NonNull @org.jetbrains.annotations.NotNull LifecycleOwner owner) {
                
            }
        });

问题来了:是否需要在Activity.onDestroy()里移除观察者呢?
我们知道,匿名内部类持有外部类引用,addObserver(xx),这个xx 对象持有了Activity,通常来说看到这样的写法我们立马就关联到了:若是xx没有被释放,那么当Activity 销毁时,Activity 对象是无法被释放的,因为它被xx持有。
因此大部分时候我们需要在Activity.onDestroy() 里removeObserver(xx)。

接着来看看getLifecycle().addObserver(xx)此种情况是否需要主动移除observer。问题的关键是xx被谁持有了。
通过前面的分析可知,xx 被封装为ObserverWithState 对象,最后存储到Map里。而这个Map为:

#LifecycleRegistry.java
    private FastSafeIterableMap<LifecycleObserver, ObserverWithState> mObserverMap =
            new FastSafeIterableMap<>();

它是LifecycleRegistry 的成员变量,而LifecycleRegistry 对象是ComponentActivity 的成员变量,最终结果:Map 是LifeActivity 的成员变量。
当Activity 销毁时,Map将会被销毁,而Map 将不会再持有Observer。
因此,得出的结论是:

无需调用getLifecycle().removeObserver(observer);

内存泄漏的本质是:长生命周期的对象持有短生命周期对象的引用,导致短生命周期对象无法释放。

5、总结

本篇文章并没有将侧重点放在Lifecycle.State 与Lifecycle.Event 之间的转换,而是着眼于为什么需要Lifecycle以及Lifecycle 如何感知生命周期,希望能够自然而然地引入Lifecycle,并了解其设计原理。
Lifecycle 是LiveData的基础,接下来将会分析LiveData的妙用。

本文基于:implementation 'androidx.appcompat:appcompat:1.4.1'

Lifecycle 源码测试

您若喜欢,请点赞、关注,您的鼓励是我前进的动力

持续更新中,和我一起步步为营系统、深入学习Android

1、Android各种Context的前世今生
2、Android DecorView 必知必会
3、Window/WindowManager 不可不知之事
4、View Measure/Layout/Draw 真明白了
5、Android事件分发全套服务
6、Android invalidate/postInvalidate/requestLayout 彻底厘清
7、Android Window 如何确定大小/onMeasure()多次执行原因
8、Android事件驱动Handler-Message-Looper解析
9、Android 键盘一招搞定
10、Android 各种坐标彻底明了
11、Android Activity/Window/View 的background
12、Android Activity创建到View的显示过
13、Android IPC 系列
14、Android 存储系列
15、Java 并发系列不再疑惑
16、Java 线程池系列
17、Android Jetpack 前置基础系列
18、Android Jetpack 易懂易学系列

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

推荐阅读更多精彩内容