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

news2024/11/20 14:22:13

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: LifecycleCoroutineScope
    get() = 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
    @Override
    protected 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); //注入ReportFragment
        if (BuildCompat.isAtLeastT()) {
            mOnBackPressedDispatcher.setOnBackInvokedDispatcher(
                    Api33Impl.getOnBackInvokedDispatcher(this)
            );
        }
        if (mContentLayoutId != 0) {
            setContentView(mContentLayoutId);
        }
    }

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

        @JvmStatic
        fun injectIfNeededIn(activity: Activity) {
            if (Build.VERSION.SDK_INT >= 29) {
                // On API 29+, we can register for the correct Lifecycle callbacks directly
                LifecycleCallbacks.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 events
            val manager = activity.fragmentManager
            if (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方法,从名字就可以看出来这是一个用来分发生命周期事件的方法,马上进入到这个方法之中:

        @JvmStatic
        internal 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).lifecycle
                if (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 = next
        if (handlingEvent || addingObserverCounter != 0) {
            newEventOccurred = true
            // we will figure out what to do on upper level.
            return
        }
        handlingEvent = true
        sync()
        handlingEvent = false
        if (state == State.DESTROYED) {
            observerMap = FastSafeIterableMap()
        }
    }

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

        public val targetState: State
            get() {
                when (this) {
                    ON_CREATE, ON_STOP -> return State.CREATED
                    ON_START, ON_PAUSE -> return State.STARTED
                    ON_RESUME -> return State.RESUMED
                    ON_DESTROY -> return State.DESTROYED
                    ON_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 //新事件发生标志位为false
            if (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: State
        var lifecycleObserver: LifecycleEventObserver

        init {
            lifecycleObserver = Lifecycling.lifecycleEventObserver(observer!!)
            state = initialState
        }

        fun dispatchEvent(owner: LifecycleOwner?, event: Event) {
            val newState = event.targetState
            state = 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.coloradmin.cn/o/1035252.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【05】FISCOBCOS中的节点配置

官方文档https://fisco-bcos-documentation.readthedocs.io/zh_CN/latest/docs/manual/configuration.html 配置黑名单列表 基于防作恶考虑&#xff0c;FISCO BCOS允许节点将不受信任的节点加入到黑名单列表&#xff0c;并拒绝与这些黑名单节点建立连接&#xff0c;通过[certif…

MySQL数据库的索引和事务

目录 一、索引 1.1Mysql索引 1.2索引的作用 1.3 创建索引的依据 1.4 普通索引 修改表方式创建索引 删除索引 1.5 唯一索引 修改表方式创建 删除索引 1.6 主键索引 修改表方式创建 1.7 组合索引 1.8 全文索引 1.9查看索引 二、事务 2.1事务概念 2.2事务的ACID特…

Java 核心技术卷 I —— 第2章 Java 编程环境

文章目录 2.1 安装 Java 开发工具包&#xff08;*&#xff09;2.2 使用命令行工具2.3 使用集成开发环境&#xff08;*&#xff09;2.4 JShell 2.1 安装 Java 开发工具包&#xff08;*&#xff09; 2.2 使用命令行工具 ​ 打开终端窗口&#xff0c;进入 Java 的 bin 目录&…

Linux Mint大动作:全新设计Software Manager,大幅提升用户体验

Clem Lefebvre在Linux Mint博客上宣布&#xff0c;团队已经着手开发新版本。新版本中将版本全新设计的Software Manager&#xff0c;带来更卓越更现代化的界面大幅提升用户体验。 全新的Software Manager会迎来大量变动&#xff0c;包括的内容包括&#xff1a; 用户界面看起来…

别再乱写git commit了

B站|公众号&#xff1a;啥都会一点的研究生 写在前面 在很长的一段时间中&#xff0c;使用git commit都是随心所欲&#xff0c;log肥肠简洁&#xff0c;随着代码的迭代&#xff0c;当时有多偷懒&#xff0c;返过头查看git日志就有多懊悔&#xff0c;就和写代码不写doc string…

Super Marker插件——标记资源,提高效率

插件介绍&#xff1a; 这是一款可以给资源添加颜色或图标标记&#x1f4cc;的插件&#xff0c;当资源文件比较多的时候&#xff0c;颜色标记可以让你一眼定位到要使用的资源&#xff0c;提高开发效率。 插件地址&#xff1a; Cocos商店&#xff1a;https://store.cocos.com/a…

工业蒸汽量预测(速通一)

工业蒸汽量预测&#xff08;一&#xff09; 赛题理解1、评估指标2、赛题模型3、解题思路 理论知识1、变量识别2、变量分析3、缺失值处理4、异常值处理5、变量转换6、新变量生成 数据探索1、导包2、读取数据3、查看数据4、可视化数据分布4.1箱型图4.2获取异常数据并画图4.3直方图…

【RabbitMQ实战】04 RabbitMQ的基本概念:Exchange,Queue,Channel等

一、简介 Message Queue的需求由来已久&#xff0c;80年代最早在金融交易中&#xff0c;高盛等公司采用Teknekron公司的产品&#xff0c;当时的Message queuing软件叫做&#xff1a;the information bus&#xff08;TIB&#xff09;。 TIB被电信和通讯公司采用&#xff0c;路透…

某度sign参数逆向

文章目录 前文分析完整代码结尾 前文 本文章中所有内容仅供学习交流&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff0c;若有侵权&#xff0c;请联系我立即删除&#xff01; 分析 经过我们几次抓包&#xff0c;测试&#xf…

单片机IAP固件升级分几步?(Qt上位机)

更新 0924&#xff0c;一些潜在的bug解决方案 前言 这周一直想做一个IAP固件升级的上位机&#xff0c;然后把升级流程全都搞懂。 我用的单片机型号是STM32F103VET6&#xff0c;FLASH容量是512K&#xff0c;FLASH单页是2K。 有纰漏请指出&#xff0c;转载请说明。 学习交流…

Rabbit消息的可靠性

Confirm模式简介 消息的confirm确认机制&#xff0c;是指生产者投递消息后&#xff0c;到达了消息服务器Broker里面的exchange交换机&#xff0c;则会给生产者一个应答&#xff0c;生产者接收到应答&#xff0c;用来确定这条消息是否正常的发送到Broker的exchange中&#xff…

黑马JVM总结(二十二)

&#xff08;1&#xff09;类的结构-field 成员变量信息 类字节码里的一些简单表示&#xff1a; &#xff08;2&#xff09;类文件结构-method-init &#xff08;3&#xff09;类文件结构-method-main &#xff08;4&#xff09;类文件结构-附加属性

Java基础(六)

前言&#xff1a;本篇博客学习Junit单元测试框架的使用以及常见的注解。 目录 单元测试 Junit单元测试框架 常见注解 单元测试 什么是单元测试&#xff1f; 针对最小的功能单元&#xff08;方法&#xff09;&#xff0c;编写测试代码对其进行正确性测试。 Junit单元测试框…

十六、MySql的MVCC机制CONNECT(收官!)

文章目录 一、数据库并发的场景有三种&#xff1a;二、读-写&#xff08;一&#xff09;3个记录隐藏列字段&#xff08;二&#xff09;undo 日志&#xff08;三&#xff09;模拟 MVCC&#xff08;四&#xff09;一些思考&#xff08;五&#xff09;Read View 一、数据库并发的场…

interview6-jvm篇

JVM(Java Virtual Machine)Java程序的运行环境&#xff08;java二进制字节码的运行环境&#xff09; 在JVM中共有四大部分&#xff0c;分别是ClassLoader&#xff08;类加载器&#xff09;、Runtime DataArea&#xff08;运行时数据区&#xff0c;内存分区&#xff09;、Execu…

整合车辆出险报告Api接口,轻松管理车险理赔!

随着车辆保有量的不断增加&#xff0c;车辆出险的情况也越来越普遍。对于车主来说&#xff0c;如何高效地管理车险理赔&#xff0c;处理保险事故是非常重要的。这时候我们就可以借助整合车辆出险报告API接口&#xff0c;实现快速定位理赔信息&#xff0c;轻松管理车险理赔。 一…

【C++面向对象侯捷】8.栈,堆和内存管理

文章目录 栈&#xff0c;堆stack object的生命周期static local object的生命周期global object的生命周期heap objects 的生命期new&#xff1a;先分配memory&#xff0c;再调用构造函数delete: 先调用析构函数&#xff0c;再释放 memory动态分配所得的内存块&#xff0c;in V…

VirtualBox解决VERR_SUPDRV_COMPONENT_NOT_FOUND错误

简述 最近使用VirtualBox时发现其增强功能不能用了&#xff0c;也就是不能双向拖拉文件&#xff0c;整了很久不知所以&#xff1b;看到有网友说跟新其VBoxGuestAdditions.ios文件&#xff0c;所以直接把我的VirtualBox从6.x升级到了7.x&#xff0c;然后就发生了眼前的一幕&…

040_小驰私房菜_MTK平台,添加camera客制化size

全网最具价值的Android Camera开发学习系列资料~ 作者:8年Android Camera开发,从Camera app一直做到Hal和驱动~ 欢迎订阅,相信能扩展你的知识面,提升个人能力~ 【问题背景:】mtk8195平台,录像需要添加一组自定义size 2560 * 1600。 添加一组自定义size,我们需要确认一…

数据湖在爱奇艺数据中台的应用

01 我们眼中的数据湖 作为爱奇艺的数据中台团队&#xff0c;我们的核心任务是管理和服务公司内的大量数据资产。在实施数据治理的过程中&#xff0c;我们不断吸收新的理念&#xff0c;引入尖端的工具&#xff0c;以精细化我们的数据体系管理。“数据湖”作为近年来数据领域广泛…