上一篇我们讲到了架构组件中的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. idea创建Spring项目时选择Maven还是Spring initializr?

    今天在使用idea创建Spring项目时不知道选择Maven还是Spring initializr 接着都实验了一下,其实本质是一样的,使用"spring initializr"创 ...

  2. 内核不中断前提下,Gaussdb(DWS)内存报错排查方法

    摘要:本文主要讲解如何在内核保证操作不能中断采取的特殊处理,理论上用户执行的sql使用的内存(dynamic_used_memory) 是不会大范围的超过max_dynamic_memory的内存的 ...

  3. 父组件传值给子组件时 ,watch props 监听不到解决方案

    watch:{ data:{ immediate:true, handler:function(){ } } }

  4. Element.scrollIntoView() 方法让当前的元素滚动到浏览器窗口的可视区域内

    Element.scrollIntoView() 方法让当前的元素滚动到浏览器窗口的可视区域内 语法 element.scrollIntoView(); // 等同于element.scrollInt ...

  5. 逍遥自在学C语言 | 位运算符&的高级用法

    前言 在上一篇文章中,我们介绍了&运算符的基础用法,本篇文章,我们将介绍& 运算符的一些高级用法. 一.人物简介 第一位闪亮登场,有请今后会一直教我们C语言的老师 -- 自在. 第二位 ...

  6. 从Chat-GPT看爆火技术概念及医疗领域科技与应用场景

    作者:京东健康 陈刚 一.前言 最近OpenAI在官网上宣告了多模态大模型 GPT-4 的诞生,它可能是迄今为止最好的多模态模型. 主要更新内容如下: 1. 逻辑分析能力更加全面.「考试」能力大幅提升 ...

  7. Tmux 使用教程

    本文转载自阮一峰老师的博客文章<Tmux 使用教程>,感谢阮老师! Tmux 是一个终端复用器(terminal multiplexer),非常有用,属于常用的开发工具. 本文介绍如何使用 ...

  8. React redux toolkit: Uncaught Error:[Immer] An immer producer returned a new...

    React在写一个购物车的redux toolkit时遇到了问题.核心代码如下: import { createSlice } from "@reduxjs/toolkit"; c ...

  9. Kubuesphere部署Ruoyi(三):持久化存储配置

    按照如下教程配置NFS 先服务器: https://kubesphere.io/zh/docs/v3.3/reference/storage-system-installation/nfs-serve ...

  10. 密码学与网安——intro

    Terminology primitive: 原语 (一种不可分割的最基础操作,跟具体的视角和情形有关) 两个时间节点 1949年(1945年):Shannon 提出完全安全性,开始现代密码学 197 ...