Jetpack管理生命周期——Lifecycle

news2024/9/20 18:41:17

Android Jetpack

对于任何一个产品来说,我们开发中都会面对哪些问题?如:产品交互、用户体验、代码结构、数据获取、数据存储、网络优化、任务调度等等,虽然在现在的阶段这些问题已经有了很好的解决和优化,也有很多大神的开源组件方便开发者去使用,Android Jetpack就是Google给出的一个官方的处理方法(当然知识处理其中基本问题),Android Jetpack组件的优势:

轻松管理应用程序的生命周期构建可观察的数据对象,以便在基础数据库更改时通知视图存储在应用程序轮换中未销毁的UI相关数据,在界面重建后恢复数据轻松的实现SQLite数据库系统自动调度后台任务的执行,优化使用性能

Android Jetpack组件推荐的使用项目架构

上面架构组件的功能如下:

Activity和Fragment负责产品与用户的交互ViewModel作为数据的存储和驱动Resposity负责调度数据的获取Room储存本地序列化的数据Retrofit获取远程数据的数据

Jetpack组件 Lifecycle 介绍

早期的架构中,生命周期的事件监听和状态查询,需要直接在Activity/Fragment的生命周期钩子中处理。而实际开发中,往往需要在Activity/Fragment外部进行事件监听和状态查询。在Lifecycle引入前,需要开发者自定义一套提供侦测功能的Activity/Fragment基类及回调接口。

Lifecycle的引入,即是对以上需求的官方支持。类似的,在官方推出ViewModels以前,已经存在通过Fragment实现相同功能的方案。

Lifecycler的原理:

Lifecycler为每个活动组件添加了一个没有界面的Fragment,利用Fragment周期会根据活动声明周期变化的特性实现的特性,从而实现生命周期的感知,然后根据注解的Event查找执行相应的方法。

如何管理生命周期

Lifecycle的出现帮我们解决生命周期管理的问题。这一块对于我们日常开发来说的确是比较坑的一点,生命周期处理不当,很容易造成内存泄漏。 为了能让我们业务代码能够感知到生命周期,我们可能会写大量的代码。比如在让Presenter拥有感知生命周期的能力,我们可能会这么做:

public interface IPresenter {
    void onCreate();
​
    void onStart();
​
    void onResume();
​
    void onPause();
​
    void onStop();
​
    void onDestroy();
}

然后实现接口,在Activity/Fragment的生命周期中调用这个接口,完成工作。

这种方式完全ojbk。通俗易懂,这里我不评价它的好坏,毕竟没有任何一种解决方案是完美的。所以接下来咱们来看一看官方的Lifecycle是怎样的一种思路。

Lifecycle

说破天,这里需要解决的问题是生命周期管理。那么终究还是逃脱不掉一些套路成分在其中。Lifecycle也是如此,从官方的解释中,可见一斑:

Lifecycle is a class that holds the information about the lifecycle state of a component (like an activity or a fragment) and allows other objects to observe this state.

短短一段话,我们可以猜测到这里通过观察者模式的思路去对外响应生命周期变化。闲话少说,直接从代码感受一下。

使用

从使用上来说,还是比较简单的。实现LifecycleObserver接口:

// 官方demo
class MyObserver : LifecycleObserver {
​
    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    fun connectListener() {
        // TODO
    }
​
    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    fun disconnectListener() {
        // TODO
    }
}

这俩个注解则标志着,当监听组件的onResume()方法被调用,这里我们被注解的方法也会被调用。(当然前提是addObserver了)

有了观察者了,那我们就去找被观察者。很明显,我们想要观察的对象是拥有生命周期的家伙,比如我们常用的Activity/Fragment。此时我们只需要在onResume()之前的某个实际,把这个Observer,add进去即可,比如在onCreate()中:

override fun onCreate(savedInstanceState: Bundle?) {
   lifecycle.addObserver(MyObserver())
}

OK,这样之后我们的MyObserver既可以正常在响应对应生命周期注解下的方法了。

不过,我相信这样写的朋友,回过来喷我!根本就调不到lifecycle!!

没错,我们常规的Activitiy/Fragment就是调不到…它压根就没这这个方法。

androidx

这里解释一下,上文中lifecyle其实就是调用Activity/Fragment中的这个方法:

@Override
public Lifecycle getLifecycle() {
    return mLifecycleRegistry;
}

有朋友应该提着刀过来了,我tm没有这个方法!兄die,把刀放下,不是没有是import不一样。接下来让我们慢慢来。我使用的这个Fragment的package是这样的:androidx.fragment.app;。看到端倪了吧?androidx,没错,这是为了完美支持JatPack所重新规划出来的包。

当然,也不一定非要用androidx。

Fragments and Activities in Support Library 26.1.0 and later already implement the LifecycleOwner interface.

所以,升库就ok了。这时有小伙伴可能会说了:我不想升库怎么办。这个问题问得好,不想升库,不想升库…就不升呗。

当然我相信,一定有小伙伴注意到一个问题,那就是getLifecycle()是一个接口,那么也就是说我们可以自己实现?没错是这样…(这tm不废话么)

这就是我们自定义的关键。

LifecycleOwner

假设我们的Activity不支持getLifecycle()咋整?这里直接上官方的代码:

class="prism language-kotlin">class="token keyword">class MyActivity class="token operator">: class="token function">Activityclass="token punctuation">(class="token punctuation">)class="token punctuation">, LifecycleOwner class="token punctuation">{
    class="token keyword">private class="token keyword">lateinit class="token keyword">var mLifecycleRegistryclass="token operator">: LifecycleRegistry
​
    class="token keyword">override class="token keyword">fun class="token function">onCreateclass="token punctuation">(savedInstanceStateclass="token operator">: Bundleclass="token operator">?class="token punctuation">) class="token punctuation">{
        class="token keyword">superclass="token punctuation">.class="token function">onCreateclass="token punctuation">(savedInstanceStateclass="token punctuation">)
​
        mLifecycleRegistry class="token operator">= class="token function">LifecycleRegistryclass="token punctuation">(class="token keyword">thisclass="token punctuation">)
        mLifecycleRegistryclass="token punctuation">.class="token function">markStateclass="token punctuation">(Lifecycleclass="token punctuation">.Stateclass="token punctuation">.CREATEDclass="token punctuation">)
        
        mLifecycleRegistryclass="token punctuation">.class="token function">addObserverclass="token punctuation">(class="token function">MyObserverclass="token punctuation">(class="token punctuation">)class="token punctuation">)
    class="token punctuation">}
​
    class="token keyword">public class="token keyword">override class="token keyword">fun class="token function">onStartclass="token punctuation">(class="token punctuation">) class="token punctuation">{
        class="token keyword">superclass="token punctuation">.class="token function">onStartclass="token punctuation">(class="token punctuation">)
        mLifecycleRegistryclass="token punctuation">.class="token function">markStateclass="token punctuation">(Lifecycleclass="token punctuation">.Stateclass="token punctuation">.STARTEDclass="token punctuation">)
    class="token punctuation">}
​
    class="token keyword">override class="token keyword">fun class="token function">getLifecycleclass="token punctuation">(class="token punctuation">)class="token operator">: Lifecycle class="token punctuation">{
        class="token keyword">return mLifecycleRegistry
    class="token punctuation">}
class="token punctuation">}

就这样,结束了。说实话,到这就这的没有什么好讲的了。

通过代码,我们可以看出来,LifecycleRegistry是我们的被观察者,它被初始化在拥有生命周期的Activity中,而我们的Observer也被add()到其中,此外还有诸如markState(Lifecycle.State.CREATED)的方法调用。

因此,到这无需多言,各位小伙伴恐怕已经明白了Lifecycle是如何帮我们管理生命周期的了。

Lifecycle原理代码

咱们在上述的MyObserver中加了注解,所以先看看注解为我们带来了什么。通过注解生成器,我们可以看到在build中得到了下边这个class:

class="prism language-java">class="token keyword">public class="token keyword">class class="token class-name">MyObserver_LifecycleAdapter class="token keyword">implements class="token class-name">GenericLifecycleObserver class="token punctuation">{
    class="token keyword">final MyObserver mReceiverclass="token punctuation">;
​
    class="token function">LifecycleObserverDemo_LifecycleAdapterclass="token punctuation">(MyObserver receiverclass="token punctuation">) class="token punctuation">{
        class="token keyword">thisclass="token punctuation">.mReceiver class="token operator">= receiverclass="token punctuation">;
    class="token punctuation">}
​
    class="token annotation punctuation">@Override
    class="token keyword">public class="token keyword">void class="token function">onStateChangedclass="token punctuation">(LifecycleOwner ownerclass="token punctuation">, Lifecycleclass="token punctuation">.Event eventclass="token punctuation">) class="token punctuation">{
        mReceiverclass="token punctuation">.class="token function">onAnyclass="token punctuation">(ownerclass="token punctuation">,eventclass="token punctuation">)class="token punctuation">;
        class="token keyword">if class="token punctuation">(event class="token operator">== Lifecycleclass="token punctuation">.Eventclass="token punctuation">.ON_RESUMEclass="token punctuation">) class="token punctuation">{
            mReceiverclass="token punctuation">.class="token function">connectListenerclass="token punctuation">(class="token punctuation">)class="token punctuation">;
        class="token punctuation">}
​
        class="token keyword">if class="token punctuation">(event class="token operator">== Lifecycleclass="token punctuation">.Eventclass="token punctuation">.ON_PAUSEclass="token punctuation">) class="token punctuation">{
            mReceiverclass="token punctuation">.class="token function">disconnectListenerclass="token punctuation">(class="token punctuation">)class="token punctuation">;
        class="token punctuation">}
    class="token punctuation">}
​
    class="token keyword">public Object class="token function">getReceiverclass="token punctuation">(class="token punctuation">) class="token punctuation">{
        class="token keyword">return mReceiverclass="token punctuation">;
    class="token punctuation">}
class="token punctuation">}

很清晰,我们能够看到,在onStateChanged(LifecycleOwner owner, Lifecycle.Event event)中通过对应的Event就可以调用到我们MyObserver中注解的方法。

那么问题来了:onStateChanged被谁调用的呢?通过上边的例子,我们知道想要Observer能够感应生命周期要么使用内置好的Lifecycle(getLifecycle()),要么自己去实现(LifecycleOwner)。接下来咱们就分这俩种情况来看一看具体的实现原理。

自定义LifecycleOwner

这一步的源码还是比较的简单直接的,我们可以直接在LifecycleRegistry中的markState(Lifecycle.State.STARTED)一探究竟,一层层的调用下来,我们抛弃一些逻辑判断之后,可以看到一些关键的内容:

class="prism language-java">class="token keyword">static class="token keyword">class class="token class-name">ObserverWithState class="token punctuation">{
    State mStateclass="token punctuation">;
    GenericLifecycleObserver mLifecycleObserverclass="token punctuation">;
​
    class="token function">ObserverWithStateclass="token punctuation">(LifecycleObserver observerclass="token punctuation">, State initialStateclass="token punctuation">) class="token punctuation">{
        mLifecycleObserver class="token operator">= Lifecyclingclass="token punctuation">.class="token function">getCallbackclass="token punctuation">(observerclass="token punctuation">)class="token punctuation">;
        mState class="token operator">= initialStateclass="token punctuation">;
    class="token punctuation">}
​
    class="token keyword">void class="token function">dispatchEventclass="token punctuation">(LifecycleOwner ownerclass="token punctuation">, Event eventclass="token punctuation">) class="token punctuation">{
        State newState class="token operator">= class="token function">getStateAfterclass="token punctuation">(eventclass="token punctuation">)class="token punctuation">;
        mState class="token operator">= class="token function">minclass="token punctuation">(mStateclass="token punctuation">, newStateclass="token punctuation">)class="token punctuation">;
        class="token comment">// 看到这,没啥好说的了吧?
        mLifecycleObserverclass="token punctuation">.class="token function">onStateChangedclass="token punctuation">(ownerclass="token punctuation">, eventclass="token punctuation">)class="token punctuation">;
        mState class="token operator">= newStateclass="token punctuation">;
    class="token punctuation">}
class="token punctuation">}

可以看到,这部分会很直白的调用到注解生成class中的onStateChanged(),完成生命周期的感知。

getLifecycle()

getLifecycle()的方式,同样是返回了一个LifecycleRegistry。因此,最开始我认为系统因此在对应的生命周期完成对上3.1一样的调用。不过看把发现自己还是太年轻。

在SupportActivity中,的onCreate方法中,我们可以看到这样的调用:

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

是不是感觉到一丝丝熟悉?使用Fragment做生命周期分离管理在很多框架中都出现。接下来我们就好好看看这个ReportFragment。

@Override
public void onResume() {
    super.onResume();
    dispatchResume(mProcessListener);
    dispatch(Lifecycle.Event.ON_RESUME);
}
​
private void dispatch(Lifecycle.Event event) {
    Activity activity = getActivity();
    if (activity instanceof LifecycleRegistryOwner) {
        ((LifecycleRegistryOwner) activity).getLifecycle().handleLifecycleEvent(event);
        return;
    }
​
    if (activity instanceof LifecycleOwner) {
        Lifecycle lifecycle = ((LifecycleOwner) activity).getLifecycle();
        if (lifecycle instanceof LifecycleRegistry) {
            ((LifecycleRegistry) lifecycle).handleLifecycleEvent(event);
        }
    }
}

到此就重新回调到了LifecycleRegistry中的方法了。以上所述就是Jetpack中的Lifecycle管理生命周期;有关更多的Android技术进阶学习,可以参考《Android核心技术手册》这个文档笔记,点击查看里面附有30几个技术板块。

总结

这几段代码下来,我相信有的朋友已经差不多了解Lifecycle的思路了。一个很标准的观察者模式:这里的LifecycleRegistry(系统帮我们实现的Lifecycle的实现类),持有想要监听这个LifecycleOwner的Observer。然后通过markState(),去遍历所有Observer,通知其生命周期发生变化。

当然仅凭这些,对于我们来说还远远不够,因此Google还拿出了ViewModel、LiveData等相辅相成的有趣模块。

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

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

相关文章

堆球问题,开普勒猜想(格密码相关)

目录 一. 介绍 二. 历史进展分析 三.2维下的堆球问题 四. 3维下的堆球问题 五. 8维与24维下的堆球问题 总结 一. 介绍 堆球问题又叫堆球理论、最密堆积、球填充,英文为The Theory Of Sphere Packings。 堆球问题的本质就是填充一堆大小相同的球。要求这些球…

FANUC机器人通过KAREL程序实现与PLC位置坐标通信的具体方法示例

FANUC机器人通过KAREL程序实现与PLC位置坐标通信的具体方法示例 在通信IO点位数量足够的情况下,可以使用机器人的IO点传输位置数据,这里以传输机器人的实时位置为例进行说明。 基本流程如下图所示: 基本步骤可参考如下: 首先确认机器人控制柜已经安装了总线通信软件(例如…

CMMI高效实施的5大注意事项

1、明确CMMI实施目标及范围 CMMI在实施过程中,需要根据组织的实际情况,确定CMMI的实施目标和范围,制定实施的计划表,为后续组织过程改进提供明确的方向。 CMMI高效实施注意事项:实施目标及范围的确定​ 2、建立…

虹科新闻 | 虹科与b-plus正式建立合作伙伴关系,共同致力于用于ADAS/AD系统开发的VV测量解决方案

虹科b-plus 携手共创未来! 近期,虹科与德国b-plus正式建立合作伙伴关系。未来,虹科与b-plus将共同致力于提供用于ADAS/AD系统开发的V&V测量解决方案。 合作寄语 虹科CEO陈秋苑女士表示:“虹科非常期待与b-plus合作&#x…

线上研讨会报名 | 与龙智、Perforce共探大规模研发中的数字资产管理与版本控制,赢取千元大奖

2023年2月28日下午2:00,加入全球领先的数字资产管理工具厂商Perforce联合中国授权合作伙伴龙智举办的Perforce on Tour网络研讨会,除了与游戏、芯片、虚拟制作行业专家探讨并分享最佳实践外,还可以赢取惊喜大奖,包括千元华为手环、…

语言文件操作

🌱博客主页:大寄一场. 🌱系列专栏:C语言学习笔记 😘博客制作不易欢迎各位👍点赞⭐收藏➕关注 目录 前言 C语言中的文件打开和关闭 文件指针 文件的打开和关闭 fclose 文件的顺序读写 fseek ftell …

Flink-多流转换(Union、Connect、Join)

文章目录多流转换分流基本合流操作联合(Union)连接(Connect)基于时间的合流——双流联结(Join)窗口联结(Window Join)间隔联结(Interval Join)窗口同组联结&a…

【Vue3】组件数据懒加载

组件数据懒加载-基本使用 目标:通过useIntersectionObserver优化新鲜好物和人气推荐模块 电商类网站,尤其是首页,内容有好几屏,而如果一上来就加载所有屏的数据,并渲染所有屏的内容会导致首页加载很慢。 数据懒加载&a…

Java面试题--熔断和降级的区别

熔断和降级都是系统自我保护的一种机制,但二者又有所不同,它们的区别主要体现在以下几点: 概念不同 触发条件不同 归属关系不同 1.概念不同 1.1熔断概念 “熔断”一词早期来自股票市场。熔断(Circuit Breaker)也…

Python3-数据类型转换

有时候,我们需要对数据内置的类型进行转换,数据类型的转换,一般情况下你只需要将数据类型作为函数名即可。 Python 数据类型转换可以分为两种: 隐式类型转换 - 自动完成 显式类型转换 - 需要使用类型函数来转换 隐式类型转换 在…

一图说明 monorepo 落地流程方案

关于 monorepo 初次讨论已有2年载,目前团队已经沉淀了成熟的技术方案且经受住了实战考验。所以特梳理相关如下: 也算是关于之前发起的 monorepo–依赖 的解答篇。 上图为目前团队贡献的主流程:① 本地开发 > ② 提交Git仓库 > ③ 触发…

网络安全高级攻击

对分类器的高层次攻击可以分为以下三种类型:对抗性输入:这是专门设计的输入,旨在确保被误分类,以躲避检测。对抗性输入包含专门用来躲避防病毒程序的恶意文档和试图逃避垃圾邮件过滤器的电子邮件。数据中毒攻击:这涉及…

一种改善调制宽带变换器的有意混叠方法(Matlab代码实现)

👨‍🎓个人主页:研学社的博客💥💥💞💞欢迎来到本博客❤️❤️💥💥🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密…

【数组与链表算法】矩阵算法在程序中常见的简单应用 | C++

第二十三章 矩阵算法 目录 第二十三章 矩阵算法 ●前言 ●矩阵算法与深度学习 ●一、矩阵相加 ●二、矩阵相乘 ●三、矩阵转置 ●四、稀疏矩阵 ●总结 前言 数组与链表都是相当重要的结构化数据类型,也都是典型线性表的应用。线性表用于计算机中的数据存储结构…

SpringCloud-学习笔记(五)nacos集群环境搭建

参考视频 集群搭建步骤 搭建MySQL集群并初始化数据库表 下载解压nacos 修改集群配置(节点信息)、数据库配置 分别启动多个nacos节点 nginx反向代理 安装数据库 官方的建议是使用MySQL组词给模式的高可用集群,这里为了方便演示,仅…

【大厂高频必刷真题100题】《有序矩阵中第 K 小的元素》 真题练习第27题 持续更新~

有序矩阵中第 K 小的元素 给你一个 n x n 矩阵 matrix ,其中每行和每列元素均按升序排序,找到矩阵中第 k 小的元素。 请注意,它是 排序后 的第 k 小元素,而不是第 k 个 不同 的元素。 你必须找到一个内存复杂度优于 O(n^2) 的解决方案。 示例 1: 输入:matrix = [[1,5,9…

makefile编写

文章目录什么是编译器GCC 编译器编写makefile什么是编译器 C语言代码由固定的词汇按照固定的格式组织起来,简单直观,程序员容易识别和理解,但是对于CPU,C语言代码就是天书,根本不认识,CPU只认识几百个二进…

Windows 免安装版mysql,快速配置教程

简单步骤 下载并解压mysql压缩包&#xff0c;把 “<mysql根目录>/bin” 路径添加到系统环境变量path中命令行执行 mysqld --initialize --console&#xff0c;初始化data目录&#xff08;数据库表文件默认存放在" <mysql安装根目录>/data "目录下&#…

JavaScript Web API 来构建你不了解的网站

随着技术的日新月异&#xff0c;为开发人员提供了令人难以置信的新工具和API。 但据了解&#xff0c;在100 多个 API中&#xff0c;只有5%被开发人员积极使用。 随着技术的日新月异&#xff0c;为开发人员提供了令人难以置信的新工具和API。但据了解&#xff0c;在100 多个 A…

使用pytorch构建resnet50-v2

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊|接辅导、项目定制 resnet-v2改进点以及和v1差别 &#x1f9f2; 改进点&#xff1a; (a)original表示原始的ResNet的残差结构&#xff0c;(b)proposed表示新的…