沉思篇-剖析Jetpack的LiveData
上一篇我们讲到了架构组件中的Lifecycle,由于缺少具体的运用,可能缺少直观的感受,今天我们就用Lifecycle实战一回,看看Lifecycle是怎样运用到LiveData中的。
LiveData的功能
根据LiveData的类注释,我们可以知道,LiveData是一个实现了观察者模式的数据容器,并且是可感知生命周期的。由这个功能描述,我们就能知道LiveData是由两部分功能合并而来的,一部分是数据容器,一部分是响应生命周期。在阅读源码的时候,我觉得功能拆解是个很有用的手段,合理的功能拆解,就是有目的的省略,有助于快速理清功能实现逻辑。
接下来,我将以这两个功能为突破点,逐一梳理LiveData的实现思路。
LiveData的数据容器功能
数据容器的概念相信大家不会陌生,几乎每种语言都会有他们的身影,开发者用它们来保存数据对象。由于应用场景的不同,出现了各种各样的数据容器,如List,Set这些是保存数据集的,ThreadLocal是保存线程私有数据的。那么LiveData是保存什么数据的呢,它是保存可观察数据的。
对于数据容器的拆解,其实是有固定的模式可寻的,就是以添加数据为突破口,然后以数据流向为主线,逐步击破。所以我们就从LiveData添加数据的方法setValue开始分析。
setValue方法的逻辑很少,主要就是两个,增加mVersion的版本,保存数据,然后就是调用dispatchingValue进行分发了。mVersion是个关键点,后面还会讲到,这里主要是混个脸熟。我们先进入到下一步。dispatchingValue的功能很清楚,从名字上就能看出来,就是分发数据的。但是它的实现却是很巧妙的。为了阐述这个实现,我们需要一个合适的场景。假设当前LiveData保存的数据变动频繁,并且观察对象很多的情况,我们怎样快速,准确地把数据传递给观察者呢?或者换种说法,当我们正在分发数据的时候,又有新数据来了怎么办?通常来说有两种方案,掐头去尾。掐头就是在数据更新的时候不管新数据,先把分发操作执行完之后再处理新数据。去尾就是新数据来了,取消上一次数据分发,重新分发新数据。LiveData采用的是去尾的方式。明白了这点,再看dispatchingValue就很清晰了,它用mDispatchingValue标识分发状态,用mDispatchInvalidated来标识新数据状态,然后在使用for循环分发数据的时候检测mDispatchInvalidated的状态是不是更新了,由此确定是不是需要取消此次分发,进行新一轮的分发。其他的就没有更多奥秘可言了。considerNotify是分发给具体的观察者之后的处理逻辑。这一步就是在步骤2中的for循环里完成的。所以这里就是数据的最后一站了。这个方法需要根据观察者的两个状态来确定是不是要通知。一个就是步骤1中提到的mVersion,因为观察者也有一份自己的mLastVersion,假如mVersion比mLastVersion小的话就没必要通知了,因为每次通知之后,它两的值是一样的。另一个就是和生命周期扯上关系的mActive了。这个状态标示着当前的观察者是否处于激活状态。假如不是,则直接返回了。搞了这两个判断之后就是简单的更新mLastVersion和执行onChanged回调了。
以上三步就是LiveData的数据更新过程,重点在于处理分发这个步骤上,在以后的项目中,我们可以借鉴这种思想,当然具体问题是需要具体分析的。
在上面的步骤3中我们知道了观察者的mActive是决定LiveData响应生命周期的关键,那么接下来我们来看看这个状态是怎么更新的吧。
LiveData的生命周期感知
联系上一篇文章沉思篇-剖析JetPack的Lifecycle,我们知道Lifecycle是专业干介个的(生命周期感知)。同时文章也提到了Lifecycle三个很重要的抽象,LifecycleOwner,Lifecycle,LifecycleObserver,这是引入生命周期感知三个很好的突破口。
LifecycleOwner作为生命周期的动力源,是直接可以获得Lifecycle的,继而可以方便地读取状态和注册状态监听,由于出色的接口封装,不需要和其他类产生耦合,是个很好的引入对象。Lifecycle作为Lifecycle的核心类,它完成了很多功能,是抽象类,只能继承使用。LifecycleObserver,作为状态更新通知的最后一环,可以很方便地完成状态监听,但是需要注册到合适的Lifecycle上。
所以很显然,LiveData使用Lifecycle需要搞一个LifecycleOwner,用于引入生命周期的状态,还需要搞一个LifecycleObserver,用于响应状态更新。另外,由于我们是数据容器的定位,我们的数据是很可能供给给很多类使用的,所以假如将LifecycleOwner和LiveData绑定的话,一旦某个操作致使LiveData失活,其他所有的观察者就一摸黑了,啥也收不到了,这是有悖设计的。基于这个原因,LifecycleOwner只能和Observer绑定。结果就显而易见了,他们同时出现在了observe方法里,这也就解释了observe方法为啥需要两个参数。
很明显observe就是分析生命周期感知的突破口,我们再接再励,看看他们是怎么合力工作的。
在observe内部,LifecycleOwner和Observer同时被LifecycleBoundObserver接收,用于构造对象了,逻辑继续转到LifecycleBoundObserver中.
注意到LifecycleBoundObserver是实现了LifecycleEventObserver,并且继承自ObserverWrapper。ObserverWrapper不熟悉我们先放一边,上一篇中我们知道了LifecycleEventObserver是继承自LifecycleObserver的,它只有一个状态变更的回调。很显然,我们下一步就是去看看它是怎样处理状态变更的。
来到onStateChanged方法,里面做了两件事,而且是互斥的,这就是说,其实它在某种条件下干一件事,其他条件干另一个事。先看简单的一件事,它在Lifecycle状态是DESTROYED的时候移除了Observer,没有更多了。那么另一件事其实我们也能猜到了,就是状态不为DESTROYED的时候怎么搞。它委托给了父类ObserverWrapper搞。
逻辑来到ObserverWrapper的activeStateChanged方法里,里面就是对LiveData的状态进行设置而已,也就是根据现在是不是激活状态更新mActiveCount的值,并且在适当的条件下通知LiveData进入激活状态或者失活状态。另外就是上面我们心心念念的mActive了,这就接上了。当然,还有个极为关键的点,在激活状态下,会以自身为参数,进行一次数据数据,在某种情况下,这可能会引入数据问题。
到这里,LiveData的生命周期感知就看完了.一句话就能总结,Lifecycle让LiveData有了在激活状态下分发数据,在失活后自动取消监听的能力。
补充说明
虽然前面讲了那么多,还有一些内容是没有讲到的,比如数据的异步更新,Observer的注册过程,等等,但是已经不妨碍我们理解主流程了。为了加深印象,我还整理一个UML图,可以对照着图再次理解,回顾。

沉思篇-剖析Jetpack的LiveData的更多相关文章
- v77.01 鸿蒙内核源码分析(消息封装篇) | 剖析LiteIpc(上)进程通讯内容 | 新的一年祝大家生龙活虎 虎虎生威
百篇博客分析|本篇为:(消息封装篇) | 剖析LiteIpc进程通讯内容 进程通讯相关篇为: v26.08 鸿蒙内核源码分析(自旋锁) | 当立贞节牌坊的好同志 v27.05 鸿蒙内核源码分析(互斥锁 ...
- v78.01 鸿蒙内核源码分析(消息映射篇) | 剖析LiteIpc(下)进程通讯机制 | 百篇博客分析OpenHarmony源码
百篇博客分析|本篇为:(消息映射篇) | 剖析LiteIpc(下)进程通讯机制 进程通讯相关篇为: v26.08 鸿蒙内核源码分析(自旋锁) | 当立贞节牌坊的好同志 v27.05 鸿蒙内核源码分析( ...
- 看过这篇剖析,你还不懂 Go sync.Map 吗?
hi, 大家好,我是 haohongfan. 本篇文章会从使用方式和原码角度剖析 sync.Map.不过不管是日常开发还是开源项目中,好像 sync.Map 并没有得到很好的利用,大家还是习惯使用 M ...
- Android JetPack~ LiveData (一) 介绍与使用
一般情况下LiveData都是搭配这ViewModel使用,这里先介绍一下LiveData,再结合ViewModel使用 Android数据绑定技术一,企业级开发 Android数据绑定技术二,企业级 ...
- Jetpack Compse 实战 —— 全新的开发体验
公众号回复 Compose 获取安装包 项目地址: Wanandroid-Compose 经过前段时间的 Android Dev Summit ,相信你已经大概了解了 Jetpack Compose ...
- WPF基础到企业应用系列7——深入剖析依赖属性(WPF/Silverlight核心)
一. 摘要 首先圣殿骑士非常高兴这个系列能得到大家的关注和支持.这个系列从七月份開始到如今才第七篇,上一篇公布是在8月2日,掐指一算有二十多天没有继续更新了,最主要原因一来是想把它写好,二来是由于近期 ...
- 大数据理论篇 - 通俗易懂,揭秘谷歌《The Dataflow Model》的核心思想(一)
目录 前言 目标 核心的设计原则 通用的数据处理流程 切合实际的解决方案 总结 延伸阅读 最后 作者:justmine 头条号:大数据达摩院 创作不易,未经授权,禁止转载,否则保留追究法律责任的权利. ...
- 反病毒攻防研究第006篇:简单木马分析与防范part2
一.前言 一般来说,木马是既有客户端也有服务器端的.上次讨论的不过是一种特殊情况,毕竟不是人人都懂得DOS命令,因此现在木马的客户端也都是做成非常直观的界面形式,方便操作.本篇文章会从客户端与服务器端 ...
- 学习Android Jetpack? 入门教程和进阶实战这里全都有!
前言 2018年谷歌I/O,Jetpack横空出世,官方介绍如下: Jetpack 是一套库.工具和指南,可帮助开发者更轻松地编写优质应用.这些组件可帮助您遵循最佳做法.让您摆脱编写样板代码的工作并简 ...
- Jetpack MVVM 实战项目,附带源码+视频,收藏!
从读者的反馈来看,近期大部分安卓开发已跳出舒适圈,开始尝试认识和应用 Jetpack MVVM 到实际的项目开发中. 只可惜,关于 Jetpack MVVM,网上多是 东拼西凑.人云亦云.通篇贴代码 ...
随机推荐
- 在Android应用中通过Chaquopy使用Python
在Android应用中通过Chaquopy使用Python [译] 通过Python脚本和包为Android应用带来更多的功能 翻译自https://proandroiddev.com/chaquop ...
- GitLab 安装部署使用
GitLab介绍 GitLab:是一个基于Git实现的在线代码仓库托管软件,你可以用gitlab自己搭建一个类似于Github一样的系统,一般用于在企业.学校等内部网络搭建git私服. 功能:Gitl ...
- 【转载】使用IntelliJ IDEA 14和Maven创建java web项目
安装Maven 下载安装 去maven官网下载最新版(传送门 密码: gfi1) 解压到安装目录. 配置 右键桌面的计算机图标,属性–>高级系统设置–>环境变量,添加M2_HOME的环境 ...
- python:调用内置函数
问题描述:尝试下博客园如何上传GIF # hzh 每天进步一点点 # 2022/5/13 17:24 import colorama import time import os colorama.in ...
- OpenAI API
OpenAI API Documentation https://platform.openai.com/docs/models/overview GPT 迭代过程 版本 发布时间 训练方案 参数量 ...
- 家用wife密码设置
1.在浏览器上面输入ip地址:http://192.168.1.1/或http://192.168.0.1/出现路由器登陆窗口输入用户名跟密码.用户名默认一般为:admin,密码为空或为:admin ...
- Rust中的Copy和Clone
1.Copy和Clone Rust中的Copy和Clonetrait都允许创建类型实例的副本.它们都提供了一种复制类型实例的方法,但它们之间存在一些重要的区别.了解这些区别有助更好地使用这两个特征. ...
- 关于Java中值传递和址传递
参数传递在Java中有两种类型 值和址 其实本质都是一份拷贝 在调用函数的时候 进行压栈 传进来的参数会被开辟一份新的空间 传基本类型是把值传过去 传引用数据类型是实例指向实参 void m(int ...
- 痞子衡嵌入式:聊聊i.MXRT1xxx上第三级启动保障 - SDMMC manufacture模式
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是i.MXRT1xxx上第三级启动保障 - SDMMC manufacture模式. 如果你在 i.MXRT1xxx 板卡上尝试过从 SD ...
- I-o-C 一篇概览
一.ioC 容器和 Bean介绍 IoC(Inversion of Control )也被称之为 DI(dependency injection),名称侧重点略有不同. 所谓控制翻转即对象通过构造函数 ...