从代码设计看 Glide 之生命周期(上)

news2024/11/18 0:37:49

欢迎关注我的其他平台账号:
掘金:0xforee
个人博客:0xforee’s blog
微信公众号:0xforee


上期我们探索了一个具备核心功能的图片加载库该怎么设计。这一期我们来看看如何给这个图片加载库关联生命周期管理。

欢迎关注本系列其他文章:

  • 从代码设计看 Glide 之写在开头
  • 从代码设计看 Glide 之核心功能
  • 从代码设计看 Glide 之生命周期(上)
  • 从代码设计看 Glide 之生命周期(中)
  • 从代码设计看 Glide 之生命周期(下)

引言

用过 Glide 一定不会对这几个方法陌生

Glide#with(android.content.Context) 
Glide#with(android.app.Activity) 
Glide#with(FragmentActivity) 
Glide#with(Fragment) 
Glide#with(android.app.Fragment) 
Glide#with(android.view.View)

那你知道为什么 Glide 要绑定 Context,Activity,Fragment 或 View 吗?

正文

为什么要关联生命周期?

让图片加载库感知和联动生命周期有个非常大的好处,就是可以让库的管理从手动档变为自动档。

上一期讲到的图片加载库的核心功能中,包括了一些例如 Request 请求管理,图片加载线程管理等的功能,如果我们按照这个设计去实现,势必要面临一个问题。页面退出时,该如何处理这些可能正在加载的请求。

一种普遍的处理方案是,我们对外提供结束请求,释放内存,释放引用的接口,在每个页面销毁的时候,手工调用框架接口完成管理。

如果用过 Android 中 Handler 的一定知道,我们要在每个页面退出的时候,remove 掉所有可能还未执行的请求,防止内存泄露。

所以如果框架可以自动帮我们结束请求,释放内存,释放引用就好了。就像我们从 C 语言迈入 Java 的那样,不再需要手动管理内存。而我们这期所关注的生命周期就可以做到这些。

总结来说,框架拥有生命周期的能力是为了:

  1. 智能管理请求和引用
  2. 内存管理,且防止内存泄露
  3. 提升开发效率,关注业务核心逻辑,而不需要处理边界和退出场景
  4. 让框架更加易用(关注少量 API 即可)

接下来我们看看 Glide 是如何实现生命周期管理的?并且它是怎么设计的?

如何实现生命周期?

Andrid Lifecycle

说起 Lifecycler 大家一定会想到 Google 官方为 Activity 和 Fragment 提供的库 android.lifecycle

2018年,Jetpack 横空出世,带来了一系列新的特性,其中就包括 Lifecycle 生命周期的库。这个库可以帮我们掌握 Activity 和 Fragment 的生命周期。让我们实现更加智能的框架。

生命周期的介绍可以参考这篇官方指引文档

Lifecycle 这个库 Android 内部也有很多地方用。比如最近几年很火的库:LiveData,其中就用了 Lifecycle,从而让数据绑定和释放更加智能。

还有系统代码 SystemUI 模块-快捷开关的部分,系统设置中的 WifiTracker 模块等等。可以说在有了 Lifecycle 库后,系统的很多功能都用 Lifecycle 重写了一遍。

以下是使用到 Lifecycle 的一些系统包示例

com.android.systemui.statusbar.phone
com.android.systemui.statusbar.policy
com.android.systemui.util
com.android.wifitrackerlib

好了,那我们就用 Lifecycle 库来探究一下如何为之前设计的图片加载库增加生命周期识别的能力。

生命周期涉及两个角色:

  1. 提供者:也就是说拥有生命周期的角色,Android 官方把它称为 LifecycleOwner,由 Activity 和 Fragment 实现。
  2. 监听者:也就是说要使用生命周期的角色,比如 Android 官方的 LiveData,还有我们即将要关联的 RequestManager

那么提供者如何把自己的生命周期告诉 RequestManager 呢?

没错。简单来说就是回调

并且因为提供者需要通知多个监听者,所以这里需要提供者维护一个监听者队列。比如这里可以用观察者模式或者订阅者模式等。

监听者通过 addObserver 把自己加到 LifecycleOwner 维护的列表中来感知生命周期。

大概是这样:

简化版生命周期

如果我们的模块比较简单这么实现也完全没问题,但 Activity 这个类要负责的事项就重多了,如果还得负责维护 Lifecycle 注册相关的一堆事项,代码会变得更加庞杂且不优雅,所以我们将这部分逻辑拆出来单独交给一个新的角色 Registry 维护。

大概会变成这样:

稍微复杂版生命周期

Registry 会专门负责维护注册 Observer 和取消注册 Observer 以及分发生命周期状态变化这些职责。

整体的使用流程是:
Client 通过 Activity 取得 Lifecycle 的实现类 LifecycleRegistry 之后,通过调用 LifecycleRegistry.addObserver() 添加一个 LifecycleObserver 的实现类 DefaultLifecycleObserver,我们就可以在 DefaultLifecycleObserver 中获取到 activity 的生命周期了。

当然,实际还比这个要复杂一点点🤏🏻。因为 Lifecycle 不仅支持注册回调监听的方式,还支持注解监听的方式。

但我们这期主要是讲 Lifecycle 的使用,Lifecycle 具体的实现我们就不展开了。如果大家感兴趣这块的代码设计思路,可以评论告诉我,后边安排上。

给 RequestManager 添加生命周期

弄明白 Lifecycle 各个角色和它的职责之后,我们看看我们的需求。这里我们使用最简化的模型来理解(降低对不重要模块的细节关注度)

我们需要让 RequestManager 来感知到 Lifecycle 的状态变化,从而实现 Request 的自动启动和停止,达到智能释放引用的目标。

所以,我们让 RequestManager 实现 LifecycleObserver,然后调用 LifecycleRegister.addObserver() 把自己加进去,就可以实现生命周期的感知了。

真的是非常简单,来个类图。(基于第二章核心功能的类图所绘,忘记了的回去补一下课)

8F2E8BC6-206A-4A4C-BD7C-E069CD51DD30.png

_

不过,不能高兴的太早了。我们回顾一下这个类图,看看有什么遗漏的地方?

想一想,我们打开一个包含多个 Fragment 的 Activity 页面的时候,会有几个 Lifecycle?

我们在上期完成的图片加载库,RequestManager 的生命周期和 Application,Glide 是一致的,他们之间是 1:1 的关系。

当我们将能力拓展到 Activity 和 Fragment 的时候,Glide 本身生命周期没有变化,但是 RequestManager 生命周期却和 Glide 不一致了,变成了 n:1 的关系。

所以类图变成了这样:

FDCCEEC7-09DB-47E0-A71B-8D84AA54E75A.png

注意 Glide 和 RequestManager 之间变成了聚合的关系

此时,Glide 需要持有一个 Map,来保存 Lifecycle 和 RequestManager 的对应关系,这样对于相同的 Lifecycle 可以复用 同样的 RequestManager,从另外一个角度来说,具有相同生命周期的 Request 们都聚合到了一个 Lifecycle 下。

我们再进一步优化一下

管理职责拆分

在我们上边 Lifecycle 简单版和复杂版的示例过程中,我们是将注册管理 LifecycleObserver 的部分从 Activity(或 Fragment )中拆出来了,是为了让 Activity 更好专注于自己的本职工作,也为了减少 Activity 本身的复杂度。

同样,Glide 作为对外的入口类,我们需要保持它的整洁和易用,专注在提供对外的简单和易用接口。所以我们同样将注册管理 RequestManager 的这部分逻辑拆出来。

新增加一个 RequestManagerRetriver 管理类角色,来根据 Lifecycle 构建 RequestManager。我们考虑到除了真正就有 Lifecycle 生命周期的 Activity 和 Fragment 外,还有一些场景会需要用到全局的生命周期去加载一些图片请求,所以我们将 Manager 的类一分为二:

  1. LifecycleRequestManagerRetriver:负责具体有 Lifecycle 的 Activity 和 Fragment 的构建 RequestManager 的情况
  2. RequestManagerRetriver:整体负责管理根据 Lifecycle 构建 RequestManager。对于没有 Lifecycle 的 Application的情况自己处理,对于有 Lifecycle 的 Activity 和 Fragment 的情况,则委派给 LifecycleRequestManagerRetriever 处理。

类图变成了这样

D6D5E5BA-D47F-4858-9ADD-24F720DABCB2.png

  1. Glide 将所有 RequestManager 的创建委托给了 RequestManagerRetriever,通过 RequestManagerRetriever.get() 方法可以获取到各个类型的 Context 所对应的 RequestManager。

  2. 其中 RequestManagerRtriever 内部又将生命周期相关的分为 Application 生命周期和其他生命周期。

  3. 这样,对于Application来说,总的请求都会交给 RequestManagerRtriever.applicationManager 来处理。

  4. 而对于其他的生命周期来说,另外委托给了 LifecycleRequestManagerRetriver,用 Android的 Lifecycle 做 Key 来持有 RequestManager。例如 Context 是 Activity 的时候,会根据 Activity 所对应的生命周期的 Lifecycle 来获取对应的 RequestManager,从而达到复用的目的。

总结

整体是不是看起来清爽多了,各个类的职责分明,每个类也不会太过复杂导致难以理解。

我们来和上期的类图合并一起看看,有忘记的同学也可以借此回顾一下。

8A6604E1-21D2-42D0-B3BE-5028967B615C.png

结束语

Glide 生命周期的代码设计其实不算特别复杂,但是因为多了一些兼容性的逻辑,以及一些编程思想在里边,所以解析的时候要照顾到方方面面的话内容还是挺多的。你应该也从标题中猜出来了,生命周期的内容还未完待续。主要是为了保证篇幅不至于过长,大家理解起来轻松一些。剩下的部分我们预计会分为 1-2 期来完成,敬请期待 _

写完这段话的时候,已经凌晨 2 点了。想到第二天还要上班就开始掉头发。但生活还得继续不是吗。看到这里的你也要加油啊。我们下期见。

(如果你觉得这篇文章写得还不错,点个赞,点个收藏,点个关注吧。深夜码字不易😭)

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

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

相关文章

PPPoE连接无法建立的排查和修复

嗨,亲爱的读者朋友们!你是否曾经遇到过PPPoE连接无法建立的问题?今天我将为你详细解析排查和修复这个问题的步骤。 检查物理连接 首先,我们需要确保物理连接没有问题。请按照以下步骤进行检查: - 检查网线是否插好&…

vue训练场练习props和$emit,实现大写输入,小写输出。

场景: 在vue官网训练场,使用训练场中的组件。 仅作为练习笔记,仅供产考。 App.vue 组件代码 方式一:Watch监听 方式二:input绑定

安卓系列机型--软扩容“system分区扩容”操作步骤解析 增加系统分区大小

感兴趣的友友要区别扩容的概念。软扩容与硬扩容。硬扩容指拆解手机字库。更换大容量的字库来达到硬扩容。例如864硬扩容为8256等等。所谓的软扩容指的是将系统默认的系统分区大小修改分区表增大分区。例如原来系统分区默认2G。修改分区表为3G大小。意义在于可以刷写有些需要扩容…

ssm+vue“魅力”繁峙宣传网站源码和论文

ssmvue“魅力”繁峙宣传网站源码和论文102 开发工具:idea 数据库mysql5.7 数据库链接工具:navcat,小海豚等 技术:ssm 摘 要 随着科学技术的飞速发展,各行各业都在努力与现代先进技术接轨,通过科技手段提高自身…

CH341 USB总线转接芯片

产品概述: CH341是一个USB总线的转接芯片,通过USB总线提供异步串口、打印口、并口以及常用的2线和4线等同步串行接口。 在异步串口方式下,CH341提供串口发送使能、串口接收就绪等交互式的速率控制信号以及常用的MODEM联络信号,用于…

css transition属性

如果想实现一些效果:比如一个div容器宽高拉伸效果,或者一些好看的有过渡的效果可以使用 定义和用法 transition 属性是一个简写属性,用于设置四个过渡属性: transition-property transition-duration transition-timing-func…

视频动态壁纸 Dynamic Wallpaper for Mac中文

Dynamic Wallpaper是一款Mac平台上的动态壁纸应用程序,它可以根据时间等因素动态切换壁纸,提供更加生动和多样化的桌面体验。 Dynamic Wallpaper包含了多个动态壁纸,用户可以根据自己的喜好选择和切换。这些动态壁纸可以根据时间等因素进行自…

目标检测后的图像上绘制边界框和标签

效果如图所示,有个遗憾就是CV2在图像上显示中文有点难,也不想用别的了,所以改成了英文,代码在下面了,一定要注意一点,就是标注文件的读取一定要根据自己的实际情况改一下,我的所有图像的标注文件…

大数据Flink(七十):SQL 动态表 连续查询

文章目录 SQL 动态表 & 连续查询 一、​​​​​​​SQL 应用于流处理的思路

【牛客网题目】反转链表

目录 描述 解题分析 描述 给定一个单链表的头结点pHead(该头节点是有值的,比如在下图,它的val是1),长度为n,反转该链表后,返回新链表的表头。 数据范围: 0≤n≤1000 要求:空间复杂度O(1) &a…

UDP 广播

一、UDP 通信图解 UDP通信、本地套接字_呵呵哒(&#xffe3;▽&#xffe3;)"的博客-CSDN博客https://blog.csdn.net/weixin_41987016/article/details/132523536?spm1001.2014.3001.5501 #include <sys/types.h> #include <sys/socket > ssize_t sendto(in…

macOS Sonoma 14beta 7(23A5337a)更新发布,附黑/白苹果系统镜像

系统介绍&#xff08;镜像请前往黑果魏叔官网下载&#xff09; 黑果魏叔8 月 31 日消息&#xff0c;苹果今日向 Mac 电脑用户推送了 macOS 14 开发者预览版 Beta 7 更新&#xff08;内部版本号&#xff1a;23A5337a&#xff09;&#xff0c;本次更新距离上次发布隔了 8 天。 …

Windows安装FFmpeg说明

下载地址 官网 Download FFmpeg Csdn ffmpeg安装包&#xff0c;ffmpeg-2023-08-28-git-b5273c619d-full-build.7z资源-CSDN文库 解压安装&#xff0c;添加环境变量 命令行输入ffmpeg 安装成功

typora使用

1.主题配置 先打开主题文件夹&#xff0c; 文件–>>偏好设置–>>外观–>>打开主题文件夹 1.1字体 修改字体需要修改css文件&#xff0c;确定当前所用主题&#xff0c;可以在typora菜单点击主题&#xff0c;看看当前勾选的是哪个主题&#xff0c;比如gith…

【狂神】Spring5笔记(1-9)

目录 首页&#xff1a; 1.Spring 1.1 简介 1.2 优点 2.IOC理论推导 3.IOC本质 4.HelloSpring ERROR 5.IOC创建对象方式 5.1、无参构造 这个是默认的 5.2、有参构造 6.Spring配置说明 6.1、别名 6.2、Bean的配置 6.3、import 7.DL依赖注入环境 7.1 构造器注入 …

【项目源码】一套基于springboot+Uniapp框架开发的智慧医院3D人体导诊系统源码

智慧医院3D人体导诊系统源码 开发语言&#xff1a;java 开发工具&#xff1a;IDEA 前端框架&#xff1a;Uniapp 后端框架&#xff1a;springboot 数 据 库&#xff1a;mysql 移 动 端&#xff1a;微信小程序、H5 “智慧导诊”以人工智能手段为依托&#xff0c;为…

苍穹外卖01-项目概述、环境搭建

项目概述、环境搭建 课程内容 软件开发整体介绍苍穹外卖项目介绍开发环境搭建导入接口文档Swagger 项目整体效果展示&#xff1a; 管理端-外卖商家使用 用户端-点餐用户使用 当我们完成该项目的学习&#xff0c;可以培养以下能力&#xff1a; 1. 软件开发整体介绍 作为一…

SPWM 与 SVPWM 原理及算法

所谓SPWM&#xff0c;就是在PWM的基础上改变了调制脉冲方式&#xff0c;脉冲宽度时间占空比按正弦规律排列&#xff0c;这样输出波形经过适当的滤波可以做到正弦波输出。它广泛地用于直流交流逆变器等&#xff0c;比如高级一些的UPS就是一个例子。三相SPWM是使用SPWM模拟市电的…

说说Omega架构

分析&回答 Omega架构我们暂且称之为混合数仓。 什么是ECS设计模式 在谈我们的解法的时候&#xff0c;必须要先提ECS的设计模式。 简单的说&#xff0c;Entity、Component、System分别代表了三类模型。 实体(Entity)&#xff1a;实体是一个普通的对象。通常&#xff0c…

北京已收录2023开学了《乡村振兴战略下传统村落文化旅游设计》中国建筑出版传媒许少辉八一新书

北京已收录2023开学了《乡村振兴战略下传统村落文化旅游设计》中国建筑出版传媒许少辉八一新书