Android Jetpack组件架构:Lifecycle的使用 和 原理

Android Jetpack组件架构:Lifecycle的使用和原理

在这里插入图片描述

导言

作为Jetpack中关于生命周期管理的核心组件,Lifecycle组件是其他比如LiveDate和ViewModel等组件的基础,本篇文章主要就将介绍关于Lifecycle的使用和它的运作原理。

Lifecycle的使用

我们先从Google官网上拉一段示例代码:

class MyObserver : DefaultLifecycleObserver {override fun onResume(owner: LifecycleOwner) {connect()}override fun onPause(owner: LifecycleOwner) {disconnect()}
}myLifecycleOwner.getLifecycle().addObserver(MyObserver())

可以看到这段代码首先是实现了DefaultLifecycleObserver接口,并且实现了其中的两个方法,这两个方法就是在Lifecycle组件的生命状态发生改变的时候触发的,具体来说它的作用和Activity中的各种生命周期的回调差不多。那为什么还要引入Lifecycle组件呢?原因就是为了解耦,这些年来Google越来越推崇MVVM架构,这个架构的核心思想之一就是将Activity进行解耦,尝试不要再Activity中加入过多的业务代码,要是我们直接将方法写在Activity中的话会显得整个Activity都很臃肿,切不利于我们管理,所以引入了Lifecycle组件来帮助我们管理与生命周期相关的回调。 除此之外,Lifecycle组件也是许多jetpack之中其他组件的基础。

Lifecycle的原理

Lifecycle的状态和事件

这整个Lifecycle中有两个重要的信息,一个是Lifecycle当前的状态,另一个Lifecycle状态变化而引起的事件,具体如下所示:
在这里插入图片描述
我们也可以在源码中找到:

    public enum class State {DESTROYED,INITIALIZED,CREATED,STARTED,RESUMED;public fun isAtLeast(state: State): Boolean {return compareTo(state) >= 0}}public enum class Event {ON_CREATE,ON_START,ON_RESUME,ON_PAUSE,ON_STOP,ON_DESTROY,ON_ANY; .......}

可以看到是由两个枚举类来实现的,按照Google官方文档的说法,我们可以可以将状态看作图中的节点,将事件看作这些节点之间的边(上图中)。一旦Lifecycle的状态由一个转变到另一个,就会触发它的Event事件,这个事件会被分发到观察者之中去执行响应的回调方法。

LifecycleOwner接口

LifecycleOwner的作用就是标记一个类具有生命周期,或者更具体地说,表明这个类可以由Lifecycle框架所管理,这个接口只有一个方法(成员变量),是用于获取具体的Lifecycle对象的:

public interface LifecycleOwner {/*** Returns the Lifecycle of the provider.** @return The lifecycle of the provider.*/public val lifecycle: Lifecycle
}

在Kotlin版本中这个类还有一个指向协程作用域的变量,可以在创建协程时使用:

public val LifecycleOwner.lifecycleScope: LifecycleCoroutineScopeget() = lifecycle.coroutineScope

这个接口从各个类中(具体来说是Fragment或者Activity等组件)抽象出了生命周期,并将其提供给其他组件来使用。

Activity中的Lifecycle来源

Activity肯定是一个有生命周期的组件,并且我们也可以通过getLifecycle方法获取到具体的生命周期对象,我们可以点进去,发现这个方法返回的是一个ComponentActivity类的成员变量,这个ComponentActivity类是Activity的父类:

	private final LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);public Lifecycle getLifecycle() {return mLifecycleRegistry;}

可以看到这个Activity中Lifecycle是由LifecycleRegistry实现的,一般情况下我们也是用这个类来实现Lifecycle的实体的。这个类为了防止内存泄漏是用弱引用来存储LifecycleOwner的(此处具体来说就是ComponentActivity):

private val lifecycleOwner: WeakReference<LifecycleOwner>

初次之外,其中还有几个成员变量我们先来提前介绍一下:

private var state: State = State.INITIALIZED //Lifecycle当前的State,初始化时默认是INITIALIZED 
private var observerMap = FastSafeIterableMap<LifecycleObserver, ObserverWithState>() //存储观察者的表,该表支持在迭代中修改
private var handlingEvent = false //标志位,判断当前Lifecycle是否正在处理事件

ReportFragment–用来追踪Activity生命周期变化

这里我们还是需要返回到ComponentActivity中去,Activity的Lifecycle状态是在哪里修改的呢?

    @CallSuper@Overrideprotected void onSaveInstanceState(@NonNull Bundle outState) {Lifecycle lifecycle = getLifecycle();if (lifecycle instanceof LifecycleRegistry) {((LifecycleRegistry) lifecycle).setCurrentState(Lifecycle.State.CREATED);}super.onSaveInstanceState(outState);mSavedStateRegistryController.performSave(outState);}

可以看到此处方法中的第三行将当前Lifecycle的状态设置为了CREATED,具体是从INITIALIZED 转变过去的。不过以一般的角度思考,正常应该是在ComponentActivity中的各个生命周期回调中改变,对于Actvity来说,它将这个任务交给了一个特殊的Fragment–ReportFragment,这个Fragment是在onCreate中创建出来的:

    protected void onCreate(@Nullable Bundle savedInstanceState) {mSavedStateRegistryController.performRestore(savedInstanceState);mContextAwareHelper.dispatchOnContextAvailable(this);super.onCreate(savedInstanceState);ReportFragment.injectIfNeededIn(this); //注入ReportFragmentif (BuildCompat.isAtLeastT()) {mOnBackPressedDispatcher.setOnBackInvokedDispatcher(Api33Impl.getOnBackInvokedDispatcher(this));}if (mContentLayoutId != 0) {setContentView(mContentLayoutId);}}

具体就是标注出来的ReportFragment.injectIfNeededIn(this),从命名可以看出来是一个注入方法,它将一个ReportFragment注入到了ComponentActivity之中里去了:

        @JvmStaticfun injectIfNeededIn(activity: Activity) {if (Build.VERSION.SDK_INT >= 29) {// On API 29+, we can register for the correct Lifecycle callbacks directlyLifecycleCallbacks.registerIn(activity)}// Prior to API 29 and to maintain compatibility with older versions of// ProcessLifecycleOwner (which may not be updated when lifecycle-runtime is updated and// need to support activities that don't extend from FragmentActivity from support lib),// use a framework fragment to get the correct timing of Lifecycle eventsval manager = activity.fragmentManagerif (manager.findFragmentByTag(REPORT_FRAGMENT_TAG) == null) {manager.beginTransaction().add(ReportFragment(), REPORT_FRAGMENT_TAG).commit()// Hopefully, we are the first to make a transaction.manager.executePendingTransactions()}}

这个方法首先会判断当前API版本是否大于29,如果大于就直接调用LifecycleCallbacks.registerIn(activity)方法进行注册,否则会通过Activity的FragmentManager来将ReportFragment添加进去。这个API判断不重要,反正最后做到的效果就是ComponentActivity之中有了一个用来追踪生命周期的ReportFragment了。

ReportFragment感知生命周期变化

由于是Fragment,其生命周期是由FragmentManager管理的,而这个FragmentManager又是Actvity的一部分,所以当Actvity的状态发生改变的时候会触发FragmentManager进行事件的分发,进而触发其管理下的Fragment的生命周期的变化。**总之我们记住一点,这个ReportFragment可以感知到Activity的生命周期变化。**所以,Lifecycle状态的变更应该是会在这个特殊的Fragment之中进行的,我们来看它的onActivityCreated方法:

    override fun onActivityCreated(savedInstanceState: Bundle?) {super.onActivityCreated(savedInstanceState)dispatchCreate(processListener)dispatch(Lifecycle.Event.ON_CREATE)}override fun onStart() {super.onStart()dispatchStart(processListener)dispatch(Lifecycle.Event.ON_START)}override fun onResume() {super.onResume()dispatchResume(processListener)dispatch(Lifecycle.Event.ON_RESUME)}override fun onPause() {super.onPause()dispatch(Lifecycle.Event.ON_PAUSE)}

可以看到不仅仅是onActivityCreated方法,它的其他生命周期的回调中也调用了dispatch方法,从名字就可以看出来这是一个用来分发生命周期事件的方法,马上进入到这个方法之中:

        @JvmStaticinternal fun dispatch(activity: Activity, event: Lifecycle.Event) {if (activity is LifecycleRegistryOwner) {activity.lifecycle.handleLifecycleEvent(event)return}if (activity is LifecycleOwner) {val lifecycle = (activity as LifecycleOwner).lifecycleif (lifecycle is LifecycleRegistry) {lifecycle.handleLifecycleEvent(event)}}}

可以看到主要是调用到了Activity内部的Lifecycle对象进行事件的处理。

Lifecycle处理生命周期事件

上面说到通过handleLifecycleEvent方法进行生命周期事件的处理,我们再来看这个方法:

    open fun handleLifecycleEvent(event: Event) {enforceMainThreadIfNeeded("handleLifecycleEvent")moveToState(event.targetState)}private fun moveToState(next: State) {if (state == next) {return}check(!(state == State.INITIALIZED && next == State.DESTROYED)) {"no event down from $state in component ${lifecycleOwner.get()}"}state = nextif (handlingEvent || addingObserverCounter != 0) {newEventOccurred = true// we will figure out what to do on upper level.return}handlingEvent = truesync()handlingEvent = falseif (state == State.DESTROYED) {observerMap = FastSafeIterableMap()}}

这里可以看到,主要是触发了moveToState方法,其中还涉及到event.target的取值,我们先来看这个event.target:

        public val targetState: Stateget() {when (this) {ON_CREATE, ON_STOP -> return State.CREATEDON_START, ON_PAUSE -> return State.STARTEDON_RESUME -> return State.RESUMEDON_DESTROY -> return State.DESTROYEDON_ANY -> {}}throw IllegalArgumentException("$this has no target state")}

这个方法也很好懂,根据传入的事件判断接下来Lifecycle的状态(State),如果忘了我们再来看一下那张图,可以发现完全对的上:
在这里插入图片描述
那么接下来的moveToState方法也很好懂了,就是将当前Lifecycle的状态转变到另一个状态,首先当目标状态和当前状态一致的话不会执行任何动作,接下来就直接返回。之后比较重要的部分就是sync方法了,在执行sync方法之前会将handingEvent标志位置为true,标志Lifecycle目前正在处理事件。至于这个sync方法,看名字也知道是一个用来同步内部状态的方法,具体同步的是什么呢?我们接下来继续看sync方法。

sync方法:

    private fun sync() {val lifecycleOwner = lifecycleOwner.get()?: throw IllegalStateException("LifecycleOwner of this LifecycleRegistry is already " +"garbage collected. It is too late to change lifecycle state.")while (!isSynced) { .//当当前Lifecycle还没有完成同步的话newEventOccurred = false //新事件发生标志位为falseif (state < observerMap.eldest()!!.value.state) { //判断状态转变方向backwardPass(lifecycleOwner) //向前转变}val newest = observerMap.newest() if (!newEventOccurred && newest != null && state > newest.value.state) {forwardPass(lifecycleOwner) //向后转变}}newEventOccurred = false}

首先while的判断条件是当前Lifecycle是否已经完成了必要的同步,如果还没有完成的话接下来就要进行同步。之前的方法中我们已经获得了当前Lifecycle之后要转变的状态,但是如果我们继续回看上面那张图就会发现光有一个目标状态还不行,还要判断转变的方法,比如说CREATED状态和STARTED状态,如果是向后转变要触发的应该是ON_START事件,反之则应该是ON_STOP事件。这里的if (state < observerMap.eldest()!!.value.state)以及后边的那个if分支就是用来判断状态转变的方向的。这里会涉及到观察者的生命周期,这里我们先不管,**先知道这里判断出了状态转变的方向。**我们以forwardPass方法为例看其实现。

forwardPass方法:

    private fun forwardPass(lifecycleOwner: LifecycleOwner) {@Suppress()val ascendingIterator: Iterator<Map.Entry<LifecycleObserver, ObserverWithState>> =observerMap.iteratorWithAdditions()while (ascendingIterator.hasNext() && !newEventOccurred) {val (key, observer) = ascendingIterator.next()while (observer.state < state && !newEventOccurred && observerMap.contains(key)) {pushParentState(observer.state)val event = Event.upFrom(observer.state)?: throw IllegalStateException("no event up from ${observer.state}")observer.dispatchEvent(lifecycleOwner, event)popParentState()}}}

首先会获得整个Lifecycle的Observer集合的迭代器,并且在第二个while循环中会将状态低于当前State的观察者Observer,所谓状态低我们也可以看上面那幅图,越靠近左边是State的值越小。这里我们又要考虑到这个方法是将状态向后移的情况,所以之前观察者集合中的State显然是不可能比当前State大的,所以说只要考虑observer.state < state的情况就好了。

然后会通过Event.upFrom方法获得观察者所需要的事件然后发送给对应的观察者,这样观察者就会触发其回调了,具体是observer.dispatchEvent(lifecycleOwner, event)这一行,我们来看dispatchEvent方法,这是ObserverWithState类的方法:

    internal class ObserverWithState(observer: LifecycleObserver?, initialState: State) {var state: Statevar lifecycleObserver: LifecycleEventObserverinit {lifecycleObserver = Lifecycling.lifecycleEventObserver(observer!!)state = initialState}fun dispatchEvent(owner: LifecycleOwner?, event: Event) {val newState = event.targetStatestate = min(state, newState)lifecycleObserver.onStateChanged(owner!!, event)state = newState}}

可以看到这个类主要是有两个成员变量,一个是观察者当前的状态,这个当前的状态的意思就是执行完当前Lifecycle的事件之后记录下的对应Lifecycle的State,可以说它记录的就是Lifecycle发生本次事件传递之前的状态。在其dispatchEvent方法之中最终会调用到lifecycleObserver方法,这个方法不用多说就是我们注册时传入的实现了观察者接口的方法。到这里就完成了整个Lifecycle生命感知和事件传递的过程,我们再用一幅图来总结一下:
在这里插入图片描述

LifecycleObserver接口

最后我们再来说明一下LifecycleObserver接口,具体来说这是一个标签接口,该标签的意义就是标记一个类可以用来观察Lifecycle。如果看过一些老旧的书的话,我们会发现之前这个Lifecycle的回调是用OnLifecycleEvent注解实现的,不过他现在已经被废弃了。

LifecycleObserver有两个具体子接口:DefaultLifecycleObserverLifecycleEventObserver,这两个都是可以使用的,不过一般情况下我们使用DefaultLifecycleObserver就可以了。这两个类之间也存在优先级的关系,DefaultLifecycleObserver的优先级是高于LifecycleEventObserver的,这是什么意思呢?就是一个类可以即实现DefaultLifecycleObserver类,又实现LifecycleEventObserver,这种情况下DefaultLifecycleObserver的回调将先于LifecycleEventObserver发生。

最后我们也来附一张图:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/139682.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MyBatis 中的插件可以拦截哪些操作

MyBatis 中的插件可以拦截哪些操作 MyBatis 是一个优秀的持久化框架&#xff0c;在实际项目开发中广泛应用。MyBatis 的插件机制可以方便地对 MyBatis 的各个环节进行扩展和定制。在本文中&#xff0c;我们将详细介绍 MyBatis 中的插件机制&#xff0c;并探讨插件可以拦截哪些…

C语言大佬的必杀技---宏的高级用法

C语言大佬的必杀技—宏的高级用法 目录: 字符串化标记的拼接宏的嵌套替换多条语句防止一个文件被重复包含宏和函数的区别 可能大家在学习的时候用得比较少&#xff0c;但是在一些代码量比较大的时候&#xff0c;这样使用&#xff0c;可以大大的提高代码的可读性&#xff0c;…

Dependency ‘org.redisson:redisson:‘ not found解决方法 三种刷新Maven项目的方法

报错情况 在pom中导入redisson包 <dependency><groupId>org.redisson</groupId><artifactId>redisson</artifactId> </dependency> 爆红&#xff0c;还显示Dependency org.redisson:redisson: not found。 由于报错已经解决&#xff0c;…

002-第一代硬件系统架构确立及产品选型

第一代硬件系统架构确立及产品选型 文章目录 第一代硬件系统架构确立及产品选型项目介绍摘要硬件架构硬件结构选型及设计单片机选型上位机选型扯点别的 关键字&#xff1a; Qt、 Qml、 信号采集机、 数据处理、 上位机 项目介绍 欢迎来到我们的 QML & C 项目&#xff…

【视觉SLAM入门】8. 回环检测,词袋模型,字典,感知,召回,机器学习

"见人细过 掩匿盖覆” 1. 意义2. 做法2.1 词袋模型和字典2.1.2 感知偏差和感知变异2.1.2 词袋2.1.3 字典 2.2 匹配(相似度)计算 3. 提升 前言&#xff1a; 前端提取数据&#xff0c;后端优化数据&#xff0c;但误差会累计&#xff0c;需要回环检测构建全局一致的地图&…

【AI视野·今日Sound 声学论文速览 第十期】Fri, 22 Sep 2023

AI视野今日CS.Sound 声学论文速览 Fri, 22 Sep 2023 Totally 1 papers &#x1f449;上期速览✈更多精彩请移步主页 Daily Sound Papers Performance Conditioning for Diffusion-Based Multi-Instrument Music Synthesis Authors Ben Maman, Johannes Zeitler, Meinard M lle…

【新版】系统架构设计师 - 案例分析 - 架构设计<架构风格和质量属性>

个人总结&#xff0c;仅供参考&#xff0c;欢迎加好友一起讨论 文章目录 架构 - 案例分析 - 架构设计&#xff1c;架构风格和质量属性&#xff1e;例题1例题2例题3例题4例题5例题6 架构 - 案例分析 - 架构设计&#xff1c;架构风格和质量属性&#xff1e; 例题1 某软件公司为…

Python —— pytest框架

1、认识pytest框架 1、搭建自动化框架的思路与流程 1、搭建自动化测试框架的思路和流程&#xff0c;任意测试手段流程都是一致的&#xff1a;手工测试、自动化测试、工具测试 手工测试&#xff1a;熟悉业务 —— 写用例 —— 执行用例并记录结果 —— 生成测试报告自动化测试…

Spring循环依赖大全

本博客挑出出现大部分情况的循环依赖场景进行分析&#xff0c;分析启动会不会报循环依赖的错误&#xff01; 一、常规的A依赖B&#xff0c;B依赖A&#xff0c;代码如下&#xff1a; Component public class A {Resourceprivate B b; } Component public class B {Resourcepri…

【Java 基础篇】Java函数式接口详解

Java是一门强类型、面向对象的编程语言&#xff0c;但在Java 8引入了函数式编程的概念&#xff0c;这为我们提供了更多灵活的编程方式。函数式接口是函数式编程的核心概念之一&#xff0c;本文将详细介绍Java函数式接口的概念、用法以及一些实际应用。 什么是函数式接口&#…

mall电商项目(学习记录1)

1.简介 mall项目是一套电商系统,包括前台商城系统及后台管理系统,基于SpringBoot+MyBatis实现,采用Docker容器化部署。前台商城系统包含首页门户、商品推荐、商品搜索、商品展示、购物车、订单流程、会员中心、客户服务、帮助中心等模块。后台管理系统包含商品管理、订单管…

一、 计算机网络概论

一、计算机网络概论 1、计算机网络概述 1.1、概念 计算机网络是一个将分散的、具有独立功能的计算机系统&#xff0c;通过通信设备与线路连接起来&#xff0c;由功能完善的软件实现资源共享和信息传递的系统 是一些互连的、自治的计算机系统的集合 以能够相互共享资源的方…

Python函数绘图与高等代数互融实例(八):箱线图|误差棒图|堆积图

Python函数绘图与高等代数互融实例(一):正弦函数与余弦函数 Python函数绘图与高等代数互融实例(二):闪点函数 Python函数绘图与高等代数互融实例(三):设置X|Y轴|网格线 Python函数绘图与高等代数互融实例(四):设置X|Y轴参考线|参考区域 Python函数绘图与高等代数互融实例(五…

蓝桥杯 题库 简单 每日十题 day7

01 啤酒和饮料 题目描述 本题为填空题&#xff0c;只需要算出结果后&#xff0c;在代码中使用输出语句将所填结果输出即可。啤酒每罐2.3元&#xff0c;饮料每罐1.9元。小明买了若干啤酒和饮料&#xff0c;一共花了82.3元。我们还知道他买的啤酒比饮料的数量少&#xff0c;请你…

C/C++运算符超详细讲解(系统性学习day5)

目录 前言 一、运算符的概念与分类 二、算术运算符 三、关系运算符 四、逻辑运算符 五、赋值运算符 六、运算符的优先级 总结 前言 本篇文章是对运算符的具体讲解。 一、运算符的概念与分类 概念&#xff1a; 运算符就是一种告诉编译器执行特定的数学或逻辑操作的符…

红黑树Java实现

文章目录 红黑树1. 概念性质2. 红黑树节点定义3. 红黑树的插入情况1情况2情况3其它细节问题插入代码实现 4. 红黑树的验证5.性能分析 红黑树 1. 概念性质 红黑树也是一种二插搜索树&#xff0c;每一个节点上比普通二插搜索树都增加了一个存储位置表示节点的颜色&#xff0c;可…

【已解决】ubuntu 16.04安装最新版本google chrome出错, 旧版本chrome浏览器安装流程

ubuntu 16.04 按照常规的Chrome 安装流程总是出错如下&#xff1a; Selecting previously unselected package google-chrome-stable. (Reading database ... 231747 files and directories currently installed.) Preparing to unpack google-chrome-stable_current_amd64.de…

自己写过比较蠢的代码:从失败中学习的经验

文章目录 引言1. 代码没有注释2. 长函数和复杂逻辑3. 不恰当的变量名4. 重复的代码5. 不适当的异常处理6. 硬编码的敏感信息7. 没有单元测试结论 &#x1f389; 自己写过比较蠢的代码&#xff1a;从失败中学习的经验 ☆* o(≧▽≦)o *☆嗨~我是IT陈寒&#x1f379;✨博客主页&a…

msvcr71.dll、msvcp71.dll丢失怎么办?快速修复方法分享

msvcr71.dll 是一个动态链接库文件&#xff0c;它包含了 C 运行时库的一些函数和类&#xff0c;例如全局对象、异常处理、内存管理、文件操作等。它是 Visual Studio 2003 及以上版本中的一部分&#xff0c;用于支持 C 应用程序的运行。如果 msvcr71.dll 丢失或损坏&#xff0c…

新手学习:ArcGIS对shp文件裁剪

新手学习&#xff1a;ArcGIS对SHP文件裁剪 新手学习 记录每个步骤&#xff0c;因为有很多控件可能刚开始还不熟悉&#xff0c;根本不知道在哪里&#xff0c;所以写的比较详细。 1.添加要裁剪的shp文件 2.查看shp文件的地理坐标系 双击shp文件&#xff0c;就可以查看shp文件的…