Lifecycle源码分析

目录介绍

  • 01.Lifecycle的作用是什么
  • 02.Lifecycle的简单使用
  • 03.Lifecycle的使用场景
  • 04.如何实现生命周期感知
  • 05.注解方法如何被调用
  • 06.addObserver调用分析
  • 07.知识点梳理和总结一下

00.使用AAC实现bus事件总线

  • 利用LiveData实现事件总线,替代EventBus。充分利用了生命周期感知功能,可以在activities, fragments, 或者 services生命周期是活跃状态时更新这些组件。支持发送普通事件,也可以发送粘性事件;还可以发送延迟消息,以及轮训延迟消息等等。
  • https://github.com/yangchong211/YCLiveDataBus

01.Lifecycle的作用是什么

  • Lifecycle 是一个专门用来处理生命周期的库,它能够帮助我们将 Activity、Fragment 的生命周期处理与业务逻辑处理进行完全解耦,让我们能够更加专注于业务;通过解耦让 Activity、Fragment 的代码更加可读可维护。

02.Lifecycle的简单使用

  • 直接看一下下面的案例,用法十分简单,代码如下

    • 可以通过 getLifecycle() 方法拿到 Lifecycle, 并添加 Observer 来实现对 Activity 生命周期的监听。
  • 然后打印日志记录如下所示
    • 可以发现Lifecycle是可以监听activity的生命周期的。
    • 在activity创建的时候,activity中生命周期onCreate方法优先LifecycleObserver中onCreate方法先执行;关闭的时候相反!

03.Lifecycle的使用场景

  • Lifecycle 的应用场景非常广泛,我们可以利用 Lifecycle 的机制来帮助我们将一切跟生命周期有关的业务逻辑全都剥离出去,进行完全解耦。

    • 比如视频的暂停与播放,
    • Handler 的消息移除,
    • 网络请求的取消操作,
    • Presenter 的 attach&detach View
    • 暂停和恢复动画绘制
    • 并且可以以一个更加优雅的方式实现,还我们一个更加干净可读的 Activity & Fragment。
  • 关于网络请求的取消操作
  • 停止和开启视频缓冲
    • 使用支持生命周期的组件尽快开始视频缓冲,但是将播放推迟到应用程序完全启动。 还可以使用可识别生命周期的组件在应用程序销毁时终止缓冲。
  • 启动和停止网络连接
    • 使用可感知生命周期的组件可以在应用程序处于前台状态时实时更新(流式传输)网络数据,并在应用程序进入后台时自动暂停。
  • 暂停和恢复动画绘制
    • 当应用程序在后台运行时,使用生命周期感知组件处理暂停动画绘制,并在应用程序在前台运行后恢复绘制。

04.如何实现生命周期感知

  • 看到上面的简单案例,可以发现使用了注解@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)标注的方法,既可以执行生命周期的监听。
  • 那么追踪到Lifecycle.Event类,看看还有哪里使用到了该注解,截图如下所示,这里我们就先看一下ReportFragment类,看上去应该跟Fragment有关系!

4.1 生命周期事件与状态

  • 上面案例中使用到了注解,那么它究竟有那些状态呢?

    • Lifecycle是一个抽象类,里面主要有两个功能,一个是Event生命周期,一个是State状态。
    • Lifecycle.Event表示生命周期的状态,与 Activity 生命周期类似。
    • Lifecycle.State表示当前组件的生命周期状态,
  • Event 与 State 的关系(摘自网络)

4.2 ReportFragment类分析

  • 源码如下所示,这里只是摘取了部分和生命周期有关的源代码。

    • 重写了生命周期回调的方法,可以看到生命周期方法中调用了dispatch(Lifecycle.Event.XXX),是这个 ReportFragment 在发挥作用。
    • Lifecycle 利用了 Fragment 来实现监听生命周期,并在最终利用 dispatch 的方法来分发生命周期事件。
    • 在Fragment生命周期发生变化时调用dispatch方法来分发生命周期,在里面调用了LifecycleRegistry的handleLifecycleEvent方法。
  • 然后再来看一下哪里用到了这个ReportFragment类,具体追踪到LifecycleDispatcher中的DispatcherActivityCallback内部类中的onActivityCreated方法,源码如下所示
  • 接着看一下handleLifecycleEvent(event)源码代码,可以发现根据Event状态来获取State状态,然后分发状态。后续还会分析到……

4.3 ComponentActivity类分析

  • fragment需要依赖宿主activity。通过搜索ReportFragment.injectIfNeededIn调用地方,发现 ComponentActivity 调用了该方法。(API 28 以下的版本是 SupportActivity )

    • 内部创建了一个 LifecycleRegistry 成员对象,并且该ComponentActivity类实现了 LifecycleOwner 。
    • 在 onCreate 方法里 调用了 ReportFragment.injectIfNeededIn(this); 注入了 ReportFragment。通过getLifecycle可以获取mLifecycleRegistry对象!
    • Lifecycle是一个抽象类,LifecycleRegistry是它的实现子类,主要是管理Observer,

05.注解方法如何被调用

  • OnLifecycleEvent 注解:

    • 看到有 RetentionPolicy.RUNTIME 修饰,表示运行时注解,在运行时通过反射去识别的注解。
    • 运行时注解一般和反射机制配合使用,相比编译时注解性能比较低,但灵活性好,实现起来比较简单。
  • 之前在了解完生命周期监听的原理的同时,我们也看到了生命周期事件的接收者 LifecycleRegistry ,是它的 handleLifecycleEvent() 接收了事件,我们继续追踪。
  • 其实从方法注释就能看出来了,就是它处理了状态并通知了 observer 。看下 getStateAfter() 方法:
    • getStateAfter() 这个方法根据当前 Event 获取对应的 State ,细看其实就是 【2.3.3】中那个图的代码实现。
  • 接下去看 sync() 方法:
  • sync 方法里对比了当前 mState 以及上一个 State ,看是应该前移还是后退,这个对应了生命周期的前进跟后退,打个比方就是从 onResume -> onPause (forwardPass),onPause -> onResume (backwardPass),拿 backwardPass() 举例吧。(forwardPass方法处理类似)
  • 通过源码可以看到, backwardPass() 方法调用 downEvent 获取往回退的目标 Event。可能比较抽象,举个例子,在 onResume 的状态,我们按了 home,这个时候就是 RESUMED 的状态变到 STARTED 的状态,对应的要发送的 Event 是 ON_PAUSE,这个就是 backwardPass() 的逻辑了。如果前面的代码都是引子的话,最终看到了一丝分发的痕迹了—— observer.dispatchEvent(lifecycleOwner, event)。
  • 可以看到最后调用了 GenericLifecycleObserver.onStateChanged() 方法,再跟。
    • 这个类的代码比较多,不过也不复杂。可以看到最后代码走到了invokeCallback() ,通过反射调用了方法。
    • 而这个方法是 createInfo() 方法中反射遍历我们注册的 Observer 的方法找到的被 OnLifecycleEvent 注解修饰的方法,并且按 Event 类型存储到了 info.mEventToHandlers 里。
    • 在 Observer 用注解修饰的方法,会被通过反射的方式获取,并保存下来,然后在生命周期发生改变的时候再找到对应 Event 的方法,通过反射来调用方法。

06.addObserver调用分析

  • 看一下Lifecycle中addObserver方法,发现它是一个抽象方法,那么就去找它的实现类,这里先来看一下LifecycleRegistry类中的addObserver方法实现代码

  • 然后看一下ObserverWithState类,追溯代码到Lifecycling.getCallback(observer),看看里面做了什么
  • 接着来看看Lifecycling类中getCallback方法
    • 判断该Observer是否是GenericLifecycleObserver,是的话返回本身;如果是FullLifecycleObserver,则直接创建一个FullLifecycleObserverAdapter对象
    • 判断是否包含注解处理器 查找是否包含“类名__LifecycleAdapter”的类 包含并且有OnLifecycleEvent注解则返回SingleGeneratedAdapterObserver/CompositeGeneratedAdaptersObserver
    • 如果以上提交都不满足就通过反射调用回调方法
  • 然后查看一下SingleGeneratedAdapterObserver类
    • 通过ObserverWithState#dispatchEvent方法最后调用的实际是SingleGeneratedAdapterObserver里面的onStateChanged方法
    • 在SingleGeneratedAdapterObserver里面调用了Adapter的callMethods方法
    • 这个是
  • 然后看一下CompositeGeneratedAdaptersObserver类
    • 通过ObserverWithState#dispatchEvent方法最后调用的实际是CompositeGeneratedAdaptersObserver里面的onStateChanged方法
    • 在CompositeGeneratedAdaptersObserver里面遍历mGeneratedAdapters,然后也是调用callMethods方法
  • 最后看一下ReflectiveGenericLifecycleObserver类的代码
    • 反射调用回调函数,不过这里听过class对象,从ClassesInfoCache获取info信息。先从map里拿,拿不到通过createInfo函数扫描类里面的方法。具体分析可以看源码……
  • 当addObserver的时候最后实际传入的是一个包装好的ObserverWithState对象 然后调用onStateChanged方法来分发状态。使用处理器来提高性能,避免反射造成的性能消耗。

07.知识点梳理和总结一下

  • Lifecycle 库通过在 SupportActivity 的 onCreate 中注入 ReportFragment 来感知发生命周期;
  • Lifecycle 抽象类,是 Lifecycle 库的核心类之一,它是对生命周期的抽象,定义了生命周期事件以及状态,通过它我们可以获取当前的生命周期状态,同时它也奠定了观察者模式的基调;(我是党员你看出来了吗:-D)
  • LifecycleOwner ,描述了一个拥有生命周期的组件,可以自己定义,不过通常我们不需要,直接使用 AppCompatActivity 等即可;
  • LifecycleRegistry 是Lifecycle的实现类,它负责接管生命周期事件,同时也负责Observer` 的注册以及通知;
  • ObserverWithState ,是 Observer 的一个封装类,是它最终 通过 ReflectiveGenericLifecycleObserve 调用了我们用注解修饰的方法;
  • LifecycleObserver ,Lifecycle 的观察者,利用它我们可以享受 Lifecycle 带来的能力;
  • ReflectiveGenericLifecycleObserver,它存储了我们在 Observer 里注解的方法,并在生命周期发生改变的时候最终通过反射的方式调用对应的方法。

参考博客

开源LiveData事件总线:https://github.com/yangchong211/YCLiveDataBus

Lifecycle详细分析的更多相关文章

  1. ZIP压缩算法详细分析及解压实例解释

    最近自己实现了一个ZIP压缩数据的解压程序,觉得有必要把ZIP压缩格式进行一下详细总结,数据压缩是一门通信原理和计算机科学都会涉及到的学科,在通信原理中,一般称为信源编码,在计算机科学里,一般称为数据 ...

  2. 1125MySQL Sending data导致查询很慢的问题详细分析

    -- 问题1 tablename使用主键索引反而比idx_ref_id慢的原因EXPLAIN SELECT SQL_NO_CACHE COUNT(id) FROM dbname.tbname FORC ...

  3. LinkedList详细分析

    一.源码解析1. LinkedList类定义2.LinkedList数据结构原理3.私有属性4.构造方法5.元素添加add()及原理6.删除数据remove()7.数据获取get()8.数据复制clo ...

  4. android ListView 九大重要属性详细分析、

    android ListView 九大重要属性详细分析. 1.android ListView 一些重要属性详解,兄弟朋友可以参考一下. 首先是stackFromBottom属性,这只该属性之后你做好 ...

  5. C语言中的static 详细分析

    转自:http://blog.csdn.net/keyeagle/article/details/6708077/ google了近三页的关于C语言中static的内容,发现可用的信息很少,要么长篇大 ...

  6. Linux内核OOM机制的详细分析(转)

    Linux 内核 有个机制叫OOM killer(Out-Of-Memory killer),该机制会监控那些占用内存过大,尤其是瞬间很快消耗大量内存的进程,为了 防止内存耗尽而内核会把该进程杀掉.典 ...

  7. Android-Native-Server 启动和注册详细分析

    Android-Native-Server 启动和注册详细分析     以mediaService为实例来讲解: mediaService的启动入口 是一个 传统的  main()函数 源码位置E:\ ...

  8. px,dp,dip,sp,in,mm,pt详细分析

    px,dp,dip,sp,in,mm,pt详细分析 px   :(pixels),屏幕的像素点,不同的设备显示效果相同,一般我们HVGA代表320x480像素,这个用的比较多. dip  :(devi ...

  9. Http Pipeline详细分析(下)

    Http Pipeline详细分析(下) 文章内容 接上面的章节,我们这篇要讲解的是Pipeline是执行的各种事件,我们知道,在自定义的HttpModule的Init方法里,我们可以添加自己的事件, ...

  10. 用户代理检测与浏览器Ua详细分析

    用户代理检测与浏览器Ua详细分析:http://www.cnblogs.com/hykun/p/Ua.html

随机推荐

  1. Power BI 2 DAY

    目录 Power BI零散知识点 M函数 Power BI零散知识点 纵向合并 = 主页-组合-追加查询-追加查询(修改数据源)-将查询追加为信查询(创建新数据源) 横向合并 = 主页-组合-合并查询 ...

  2. 使用memoizee缓存函数提升性能,竟引发了indexOf的性能问题

    壹 ❀ 引 公司前端组基本每个月会举行一次前端月会,用于做前端组基础设施以及其它重要信息的同步,会议最后一个环节就会分享本月前端同学在开发中所遇到的奇怪bug,或者一些有趣的问题.在分享的问题中,我发 ...

  3. NC19995 [HAOI2015]树上操作

    题目链接 题目 题目描述 有一棵点数为 N 的树,以点 1 为根,且树点有边权. 然后有 M 个 操作,分为三种: 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子 ...

  4. 使用TensorFlow实现MNIST数据集分类

    1 MNIST数据集 MNIST数据集由70000张28x28像素的黑白图片组成,每一张图片都写有0~9中的一个数字,每个像素点的灰度值在0 ~ 255(0是黑色,255是白色)之间. MINST数据 ...

  5. wordpress设置固定链接404及伪静态配置

    说明 最近在将wordpress设置中文章url修改为月份和名称型 之后访问文章出现404.原因是配有配置好apache的伪静态. 配置步骤 1.修改httpd.conf 我这里是centos7,默认 ...

  6. Spring Boot图书管理系统项目实战-8.续借图书

    导航: pre:  7.借阅图书 next:9.归还图书 只挑重点的讲,具体的请看项目源码. 1.项目源码 需要源码的朋友,请捐赠任意金额后留下邮箱发送:) 2.页面设计 2.1 bookReBorr ...

  7. Innodb 存储引擎表

    目录 索引组织表 Innodb逻辑存储结构 表空间 段 区 页 行 Innodb 行记录格式 Compact Redundant 行溢出数据 Compressed 和 Dynamic 行记录格式 ch ...

  8. Java 中拼接 String 的 N 种方式

    文章持续更新,可以关注公众号程序猿阿朗或访问未读代码博客. 本文 Github.com/niumoo/JavaNotes 已经收录,欢迎Star. 1. 前言 Java 提供了拼接 String 字符 ...

  9. WSL2镜像文件压缩

    WSL2的镜像文件(*.vhdx)支持自动扩容,但是一般不会自动缩容.一旦某次存放过大文件以后,即使后续删除,镜像文件体积仍然不会缩小,导致大量磁盘空间浪费.因此,可以定期对镜像文件进行手动压缩. 镜 ...

  10. queryset高级用法:prefetch_related

    这个方法和select_related方法类型,就是访问多个表中的数据的时候,减少查询的次数.这个方法是为了解决一对多和多对多的关系的查询问题.比如要获取标题中带有hello字符串的文章以及它的所有标 ...