上一篇我们讲到了架构组件中的Lifecycle,由于缺少具体的运用,可能缺少直观的感受,今天我们就用Lifecycle实战一回,看看Lifecycle是怎样运用到LiveData中的。

LiveData的功能

根据LiveData的类注释,我们可以知道,LiveData是一个实现了观察者模式的数据容器,并且是可感知生命周期的。由这个功能描述,我们就能知道LiveData是由两部分功能合并而来的,一部分是数据容器,一部分是响应生命周期。在阅读源码的时候,我觉得功能拆解是个很有用的手段,合理的功能拆解,就是有目的的省略,有助于快速理清功能实现逻辑。

接下来,我将以这两个功能为突破点,逐一梳理LiveData的实现思路。

LiveData的数据容器功能

数据容器的概念相信大家不会陌生,几乎每种语言都会有他们的身影,开发者用它们来保存数据对象。由于应用场景的不同,出现了各种各样的数据容器,如List,Set这些是保存数据集的,ThreadLocal是保存线程私有数据的。那么LiveData是保存什么数据的呢,它是保存可观察数据的。

对于数据容器的拆解,其实是有固定的模式可寻的,就是以添加数据为突破口,然后以数据流向为主线,逐步击破。所以我们就从LiveData添加数据的方法setValue开始分析。

  1. setValue方法的逻辑很少,主要就是两个,增加mVersion的版本,保存数据,然后就是调用dispatchingValue进行分发了。mVersion是个关键点,后面还会讲到,这里主要是混个脸熟。我们先进入到下一步。
  2. dispatchingValue的功能很清楚,从名字上就能看出来,就是分发数据的。但是它的实现却是很巧妙的。为了阐述这个实现,我们需要一个合适的场景。假设当前LiveData保存的数据变动频繁,并且观察对象很多的情况,我们怎样快速,准确地把数据传递给观察者呢?或者换种说法,当我们正在分发数据的时候,又有新数据来了怎么办?通常来说有两种方案,掐头去尾。掐头就是在数据更新的时候不管新数据,先把分发操作执行完之后再处理新数据。去尾就是新数据来了,取消上一次数据分发,重新分发新数据。LiveData采用的是去尾的方式。明白了这点,再看dispatchingValue就很清晰了,它用mDispatchingValue标识分发状态,用mDispatchInvalidated来标识新数据状态,然后在使用for循环分发数据的时候检测mDispatchInvalidated的状态是不是更新了,由此确定是不是需要取消此次分发,进行新一轮的分发。其他的就没有更多奥秘可言了。
  3. considerNotify是分发给具体的观察者之后的处理逻辑。这一步就是在步骤2中的for循环里完成的。所以这里就是数据的最后一站了。这个方法需要根据观察者的两个状态来确定是不是要通知。一个就是步骤1中提到的mVersion,因为观察者也有一份自己的mLastVersion,假如mVersionmLastVersion小的话就没必要通知了,因为每次通知之后,它两的值是一样的。另一个就是和生命周期扯上关系的mActive了。这个状态标示着当前的观察者是否处于激活状态。假如不是,则直接返回了。搞了这两个判断之后就是简单的更新mLastVersion和执行onChanged回调了。

    以上三步就是LiveData的数据更新过程,重点在于处理分发这个步骤上,在以后的项目中,我们可以借鉴这种思想,当然具体问题是需要具体分析的。

    在上面的步骤3中我们知道了观察者的mActive是决定LiveData响应生命周期的关键,那么接下来我们来看看这个状态是怎么更新的吧。

LiveData的生命周期感知

联系上一篇文章沉思篇-剖析JetPack的Lifecycle,我们知道Lifecycle是专业干介个的(生命周期感知)。同时文章也提到了Lifecycle三个很重要的抽象,LifecycleOwnerLifecycleLifecycleObserver,这是引入生命周期感知三个很好的突破口。

  • LifecycleOwner作为生命周期的动力源,是直接可以获得Lifecycle的,继而可以方便地读取状态和注册状态监听,由于出色的接口封装,不需要和其他类产生耦合,是个很好的引入对象。
  • Lifecycle作为Lifecycle的核心类,它完成了很多功能,是抽象类,只能继承使用。
  • LifecycleObserver,作为状态更新通知的最后一环,可以很方便地完成状态监听,但是需要注册到合适的Lifecycle上。

所以很显然,LiveData使用Lifecycle需要搞一个LifecycleOwner,用于引入生命周期的状态,还需要搞一个LifecycleObserver,用于响应状态更新。另外,由于我们是数据容器的定位,我们的数据是很可能供给给很多类使用的,所以假如将LifecycleOwnerLiveData绑定的话,一旦某个操作致使LiveData失活,其他所有的观察者就一摸黑了,啥也收不到了,这是有悖设计的。基于这个原因,LifecycleOwner只能和Observer绑定。结果就显而易见了,他们同时出现在了observe方法里,这也就解释了observe方法为啥需要两个参数。

很明显observe就是分析生命周期感知的突破口,我们再接再励,看看他们是怎么合力工作的。

observe内部,LifecycleOwnerObserver同时被LifecycleBoundObserver接收,用于构造对象了,逻辑继续转到LifecycleBoundObserver中.

注意到LifecycleBoundObserver是实现了LifecycleEventObserver,并且继承自ObserverWrapperObserverWrapper不熟悉我们先放一边,上一篇中我们知道了LifecycleEventObserver是继承自LifecycleObserver的,它只有一个状态变更的回调。很显然,我们下一步就是去看看它是怎样处理状态变更的。

来到onStateChanged方法,里面做了两件事,而且是互斥的,这就是说,其实它在某种条件下干一件事,其他条件干另一个事。先看简单的一件事,它在Lifecycle状态是DESTROYED的时候移除了Observer,没有更多了。那么另一件事其实我们也能猜到了,就是状态不为DESTROYED的时候怎么搞。它委托给了父类ObserverWrapper搞。

逻辑来到ObserverWrapperactiveStateChanged方法里,里面就是对LiveData的状态进行设置而已,也就是根据现在是不是激活状态更新mActiveCount的值,并且在适当的条件下通知LiveData进入激活状态或者失活状态。另外就是上面我们心心念念的mActive了,这就接上了。当然,还有个极为关键的点,在激活状态下,会以自身为参数,进行一次数据数据,在某种情况下,这可能会引入数据问题。

到这里,LiveData的生命周期感知就看完了.一句话就能总结,LifecycleLiveData有了在激活状态下分发数据,在失活后自动取消监听的能力。

补充说明

虽然前面讲了那么多,还有一些内容是没有讲到的,比如数据的异步更新,Observer的注册过程,等等,但是已经不妨碍我们理解主流程了。为了加深印象,我还整理一个UML图,可以对照着图再次理解,回顾。

沉思篇-剖析Jetpack的LiveData的更多相关文章

  1. v77.01 鸿蒙内核源码分析(消息封装篇) | 剖析LiteIpc(上)进程通讯内容 | 新的一年祝大家生龙活虎 虎虎生威

    百篇博客分析|本篇为:(消息封装篇) | 剖析LiteIpc进程通讯内容 进程通讯相关篇为: v26.08 鸿蒙内核源码分析(自旋锁) | 当立贞节牌坊的好同志 v27.05 鸿蒙内核源码分析(互斥锁 ...

  2. v78.01 鸿蒙内核源码分析(消息映射篇) | 剖析LiteIpc(下)进程通讯机制 | 百篇博客分析OpenHarmony源码

    百篇博客分析|本篇为:(消息映射篇) | 剖析LiteIpc(下)进程通讯机制 进程通讯相关篇为: v26.08 鸿蒙内核源码分析(自旋锁) | 当立贞节牌坊的好同志 v27.05 鸿蒙内核源码分析( ...

  3. 看过这篇剖析,你还不懂 Go sync.Map 吗?

    hi, 大家好,我是 haohongfan. 本篇文章会从使用方式和原码角度剖析 sync.Map.不过不管是日常开发还是开源项目中,好像 sync.Map 并没有得到很好的利用,大家还是习惯使用 M ...

  4. Android  JetPack~ LiveData (一)   介绍与使用

    一般情况下LiveData都是搭配这ViewModel使用,这里先介绍一下LiveData,再结合ViewModel使用 Android数据绑定技术一,企业级开发 Android数据绑定技术二,企业级 ...

  5. Jetpack Compse 实战 —— 全新的开发体验

    公众号回复 Compose 获取安装包 项目地址: Wanandroid-Compose 经过前段时间的 Android Dev Summit ,相信你已经大概了解了 Jetpack Compose ...

  6. WPF基础到企业应用系列7——深入剖析依赖属性(WPF/Silverlight核心)

    一. 摘要 首先圣殿骑士非常高兴这个系列能得到大家的关注和支持.这个系列从七月份開始到如今才第七篇,上一篇公布是在8月2日,掐指一算有二十多天没有继续更新了,最主要原因一来是想把它写好,二来是由于近期 ...

  7. 大数据理论篇 - 通俗易懂,揭秘谷歌《The Dataflow Model》的核心思想(一)

    目录 前言 目标 核心的设计原则 通用的数据处理流程 切合实际的解决方案 总结 延伸阅读 最后 作者:justmine 头条号:大数据达摩院 创作不易,未经授权,禁止转载,否则保留追究法律责任的权利. ...

  8. 反病毒攻防研究第006篇:简单木马分析与防范part2

    一.前言 一般来说,木马是既有客户端也有服务器端的.上次讨论的不过是一种特殊情况,毕竟不是人人都懂得DOS命令,因此现在木马的客户端也都是做成非常直观的界面形式,方便操作.本篇文章会从客户端与服务器端 ...

  9. 学习Android Jetpack? 入门教程和进阶实战这里全都有!

    前言 2018年谷歌I/O,Jetpack横空出世,官方介绍如下: Jetpack 是一套库.工具和指南,可帮助开发者更轻松地编写优质应用.这些组件可帮助您遵循最佳做法.让您摆脱编写样板代码的工作并简 ...

  10. Jetpack MVVM 实战项目,附带源码+视频,收藏!

    从读者的反馈来看,近期大部分安卓开发已跳出舒适圈,开始尝试认识和应用 Jetpack MVVM 到实际的项目开发中. 只可惜,关于 Jetpack MVVM,网上多是 东拼西凑.人云亦云.通篇贴代码  ...

随机推荐

  1. vue之写发表评论思路

    后端接口 var express = require('express'); const sql = require('../sql') const Comment = require('../sql ...

  2. ggplot2图形可视化应用集锦

    数据可视化就是将我们从数据中探索的信息与图形要素对应起来的过程.数据可视化,先要理解数据,再去掌握可视化的方法,这样才能实现高效的数据可视化.数据可视化技术的基本思想,是将数据库中每一个数据项作为单个 ...

  3. python之爬虫三

    20xpath入门 在编写爬虫程序的过程中提取信息是非常重要的环节,但是有时使用正则表达式无法匹配到想要的信息,或者书写起来非常麻烦,此时就需要用另外一种数据解析方法,也就是本节要介绍的 Xpath ...

  4. [Linux]Windows远程CENTOS7桌面

    1 背景/问题描述 客户要在CENTOS7上运行我司的基于Java的一款图形化桌面软件,然后在Windows上远程该机器的桌面软件进行操作使用.但问题是,客户的CENTOS7服务器没有图形化桌面环境, ...

  5. Oracle AUD审计 找出锁定用户的客户端IP

    问题描述:运用AUD审计找出锁定用户的客户端IP 1.查询被锁用户 SELECT USERNAME, ACCOUNT_STATUS, LOCK_DATE FROM DBA_USERS WHERE AC ...

  6. JUC(二)线程间通信

    目录 线程间通信 多线程编程步骤 一个加减实例 & 虚假唤醒问题 Lock接口实现 lock.newCondition设置等待条件 线程间定制化通信 线程间通信案例 设置标志位 线程间通信 多 ...

  7. 如何确定 this 指向?改变 this 指向的方式有哪些?

    this 指向: 1. 全局上下文(函数外) 无论是否为严格模式,均指向全局对象.注意:严格模式下全局对象为undifined 2. 函数上下文(函数内) 默认的,指向函数的调用对象,且是最直接的调用 ...

  8. TEC-6计算机组成原理实验(简图)

    TEC-6计算机组成原理实验

  9. Mysql查询执行报错Packet for query is too large (6,831,159 > 4,194,304)

    根据意思可以看出 mysql执行的报文过大.需要我们设置允许的最大报文max_allowed_packet: org.springframework.dao.TransientDataAccessRe ...

  10. Golang defer使用

    学习于https://www.liwenzhou.com/posts/Go/function/的文章 1. defer的执行顺序类似于栈,"后进先出",也就是最先defer的语句最 ...