LiveData源码解析
基于: macOs:10.14/AS:3.4/Android build-tools:28.0.0
思路
看源码前先考虑下如果要自己实现 LiveData
应该怎么做?
基本做法:
- 目标数据私有;
- 开放
setter
方法用于更新目标数据; - 提供方法添加数据变化监听器(
Observer
);
扩展:
- 允许子线程更新数据, 因此
setter
需要考虑同步; - 项目中可能多个地方需要用到目标数据,因此回调监听器可以添加多个;
- 数据变化时常常都需要更新UI,而UI有生命周期,因此
Observer
需要提供Lifecycle
相关逻辑支持,包括:- 定义处于哪些生命周期的
Observer
可以收到数据更新; onDestroy()
时自动移除Observer
等;
- 定义处于哪些生命周期的
- 如何定义
数据变化
呢? 最简单直接的做法是每次触发setter
方法时都当作数据发生了变化, 遍历通知所有Observer
即可, 更进一步的判定交给调用方; ......
简单使用
// 定义 livedata
object ParaConfig {// 定义一个私有的 `MutableLiveData`private val msgLiveData = MutableLiveData<String>()// 开放给外部获取数据更新时,提供不可变的 `LiveData` 即可;fun getMsgLiveData(): LiveData<String> = msgLiveDatafun updateMsg(msg: String, inBgThread: Boolean = false) {if (inBgThread) {msgLiveData.postValue(msg) // 在子线程中更新数据} else {msgLiveData.value = msg // 在主线程中更新数据}}
}
复制代码
// 添加 `Observer`
class LiveDataFrag : Fragment() {override fun onViewCreated(view: View, savedInstanceState: Bundle?) {super.onViewCreated(view, savedInstanceState)// 添加一个跟生命周期相关的 `Observer`ParaConfig.getMsgLiveData().observe(this, Observer<String> { newMsg ->tv_msg.text = newMsg})// 无视生命周期, 每次数据变化时都会回调,需要自行移除observerParaConfig.getMsgLiveData().observeForever {Logger.d("observeForever: $it","tag_livedata")}}
}
复制代码
看源码我还是习惯从调用入口一步步往下看, 以下也是按照这种顺序来;
实现
添加 Observer
// LiveData.java
public abstract class LiveData<T> {private static final Object NOT_SET = new Object();// 实际数据,类型为 Object 而非 Tprivate volatile Object mData = NOT_SET;// 存储所有的 Observerprivate SafeIterableMap<Observer<T>, ObserverWrapper> mObservers = new SafeIterableMap<>();// 添加跟生命周期相关的 observer// 目标数据@MainThreadpublic void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {// 若 LifecycleOwner 已处于已被销毁,则忽略该 observerif (owner.getLifecycle().getCurrentState() == DESTROYED) {return;}// 将 LifecycleOwner 和 Observer 功能进行绑定包装// 生成支持生命周期感知的 Observer: LifecycleBoundObserverLifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);// 避免重复添加相同的observerObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);if (existing != null && !existing.isAttachedTo(owner)) {throw new IllegalArgumentException("Cannot add the same observer"+ " with different lifecycles");}if (existing != null) {return;}// 实现对 LifecycleOwner 生命周期的感知// 关键还是 LifecycleBoundObserver 类,我们马上进去看一下owner.getLifecycle().addObserver(wrapper);}// 无视生命周期, 每次数据发生变化时,都会回调通知 Observer// 需要手动在不需要时移除 Observer@MainThreadpublic void observeForever(@NonNull Observer<T> observer) {AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer);ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);if (existing != null && existing instanceof LiveData.LifecycleBoundObserver) {throw new IllegalArgumentException("Cannot add the same observer"+ " with different lifecycles");}if (existing != null) {return;}wrapper.activeStateChanged(true);}
}
复制代码
MutableLiveData
只是简单重写了 LiveData
的 setValue(T)
/postValue(T)
方法, 改为 public
而已;
数据如何传递的: setValue(T)
解析
// LiveData.java
@MainThread
protected void setValue(T value) {// 只能在UI线程中调用,否则抛出异常,崩溃assertMainThread("setValue");mVersion++;mData = value;dispatchingValue(null);
}private boolean mDispatchingValue;// 若参数 initiator 非空,则表示只通知特定的 ObserverWrapper, 否则是回调通知所有 ObserverWrapper
// 由于只在主线程中调用,因此不用做多线程处理
private void dispatchingValue(@Nullable ObserverWrapper initiator) {// 小技巧: 在遍历通知各 ObserverWrapper 期间, 若数据发生了变化, 则会重新遍历通知if (mDispatchingValue) {mDispatchInvalidated = true;return;}mDispatchingValue = true;do {mDispatchInvalidated = false;if (initiator != null) {// initiator 非空时,只更新特定 ObserverWrapperconsiderNotify(initiator); // 实际更新数据的方法initiator = null;} else { // 否则遍历更新所有 ObserverWrapperfor (Iterator<Map.Entry<Observer<T>, ObserverWrapper>> iterator =mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {considerNotify(iterator.next().getValue());// 若数据发生变化, 则退出for循环// 而外层 do...while() 判定条件为true,就会重新遍历通知各 ObserverWrapper;if (mDispatchInvalidated) {break;}}}} while (mDispatchInvalidated);mDispatchingValue = false;
}// 判断是否要将数据分发到指定的 ObserverWrapper
private void considerNotify(ObserverWrapper observer) {// 是否可以分发数据到指定的 observer, 由 mActive 来控制// 所以 mActive 很重要,具体下一节解读if (!observer.mActive) {return;}// 二次确认状态, 可能生命周期发生了变化,但 mActive 并未改变if (!observer.shouldBeActive()) {// active -> inactive 时通知更新状态// inactive 状态下就不需要分发数据了observer.activeStateChanged(false);return;}// 若 ObserverWrapper 持有的数据值已是最新版本, 自然也不用分发if (observer.mLastVersion >= mVersion) {return;}observer.mLastVersion = mVersion;// 通知 observer 数据有更新// observer.mObserver 是调用方实际传入的observer.mObserver.onChanged((T) mData);
}
复制代码
用于子线程调用的 postValue(T)
会发射一个 Runnable
到主线程中, 最终也是通过 setValue(T)
来实现数据分发; 当然, postValue(T)
也可以在主线程调用,不过是多此一举,如:
// observer会先收到 "msgFromSetValue" 然后才收到 "msgFromPostValue"
someBtnView.setOnClickListener {msgLiveData.postValue("msgFromPostValue")msgLiveData.value = "msgFromSetValue"
}
复制代码
ObserverWrapper
类解析
// LiveData 的内部抽象类
// 包装用户传入的 Observer, 提供数据版本记录以及active状态(生命周期)判断
private abstract class ObserverWrapper {final Observer<T> mObserver;boolean mActive; // 确定当前 ObserverWrapper 是否生效,true时才可进行数据更新int mLastVersion = START_VERSION; // 当前持有的数据版本号,初始值为 -1ObserverWrapper(Observer<T> observer) {mObserver = observer;}// 判断该 Observer 是否有效, true 时才会触发 activeStateChanged()abstract boolean shouldBeActive();boolean isAttachedTo(LifecycleOwner owner) {return false;}void detachObserver() {}// 更新本 ObserverWrapper 的状态void activeStateChanged(boolean newActive) {// 若状态没变化,不需要更新,直接返回if (newActive == mActive) {return;}mActive = newActive;boolean wasInactive = LiveData.this.mActiveCount == 0;LiveData.this.mActiveCount += mActive ? 1 : -1;// 处于 active 状态的 observer 数量从0 -> 1时,触发 onActive() 方法if (wasInactive && mActive) {onActive();}// 处于 active 状态的 observer 数量从 1 -> 0时,触发 onInactive() 方法// 提供给观察者释放资源的机会if (LiveData.this.mActiveCount == 0 && !mActive) {onInactive();}// observer 从 inactive -> active 时, 更新数据if (mActive) {// 将数据发送给该 observerdispatchingValue(this);}}
}
复制代码
此类并未给出 inactive/active 具体是何种状态, 具体应是由 shouldBeActive()
来确定, 因此需要从子类查找;
子类 AlwaysActiveObserver
比较简单, 只是将shouldBeActive()
固定返回 true
,表示一直生效, 每次数据发生变化时都需要发送通知; 我们看下 LifecycleBoundObserver
类;
LifecycleBoundObserver
解析
// LiveData 内部类
// 将 LifecycleObserver 和 ObserverWrapper 结合,当生命周期变化时,通知 ObserverWrapper 更新数据
class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver {@NonNull final LifecycleOwner mOwner;LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<T> observer) {super(observer);mOwner = owner;}@Overrideboolean shouldBeActive() {// 此处定义了哪些生命周期是 `active` 的// 结合 Lifecycle.State 类 ,我们知道是: STARTED/RESUMED 两种状态// 对应于生命周期 `onStart()` 之后到 `onStop()` 之前return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);}// 生命周期变化时回调本方法@Overridepublic void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {// 若当前 LifecycleOwner onDestory() 了, 则自动移除 observer, 避免内存泄露if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {removeObserver(mObserver);return;}// 将 shouldBeActive() 返回的状态当做本 ObserverWrapper 的状态// 即 mActive = shouldBeActive()activeStateChanged(shouldBeActive());}@Overrideboolean isAttachedTo(LifecycleOwner owner) {return mOwner == owner;}@Overridevoid detachObserver() {mOwner.getLifecycle().removeObserver(this);}
}
复制代码
小结
- 只能在主线程中进行
Observer
的添加:observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer)
observeForever(@NonNull Observer<T> observer)
- 添加带
LifecycleOwner
的Observer
时, 若发生onDestory()
,则会自动移除Observer
; - 数据只会在
LifecycleOwner
处于onStart()
/onResume()
/onPause()
生命周期时,才会分发; - 若处于 active 的
Observer
数量从 1 -> 0, 回调onInactive()
,适用于子类进行资源释放; - 若处于 active 的
Observer
数量从 0 -> 1, 回调onActive()
; LiveData
类和ObserverWrapper
类都会在内部持有一个数据版本号;LiveData
数据发生变化时,会切换到主线程,然后遍历所有Observer
, 并将数据分发给处于 active 状态并且数据版本号不一致的Observer
;
转载于:https://juejin.im/post/5cd907166fb9a031ef63d66c
LiveData源码解析相关推荐
- LiveData 源码解析(2.4.1 版本)
文章目录 1.LiveData 简介 2.LiveData 配置与基本用法 2.1 依赖引入与配置 2.2 基本用法 2.2.1 LiveData 简单使用 2.2.2 LiveData 扩展 2.2 ...
- Android Jetpack LiveData 源码解析
是什么 LiveData 是具备生命周期的数据,当数据放生变化的时候,如果页面已经销毁,那么就不会回调给监听者. 有什么用? 当我们获取到网络请求的数据,如果页面已经销毁了,就不会调用更新Ui 的方法 ...
- Lifecycle 源码解析(2.4.1 版本)
文章目录 1.Lifecycle 简介 2.Lifecycle 配置与基本用法 2.1 依赖引入与配置 2.2 基本用法 2.2.1 Lifecycle 简单使用 2.2.2 普通 Activity ...
- ViewModel 源码解析
MVVM架构中,会用到ViewModel类,那么这个类原理是什么呢?有什么好处呢? 第一部分:源码文档解析 /*** ViewModel is a class that is responsible ...
- 5. Jetpack源码解析---ViewModel基本使用及源码解析
截止到目前为止,JetpackNote源码分析的文章已经有四篇文章了,这一系列的文章我的初衷是想仔细研究一下Jetpack,最终使用Jetpack组件写一个Demo,上一篇已经分析了LiveData, ...
- 谷歌BERT预训练源码解析(二):模型构建
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/weixin_39470744/arti ...
- 谷歌BERT预训练源码解析(三):训练过程
目录 前言 源码解析 主函数 自定义模型 遮蔽词预测 下一句预测 规范化数据集 前言 本部分介绍BERT训练过程,BERT模型训练过程是在自己的TPU上进行的,这部分我没做过研究所以不做深入探讨.BE ...
- 谷歌BERT预训练源码解析(一):训练数据生成
目录 预训练源码结构简介 输入输出 源码解析 参数 主函数 创建训练实例 下一句预测&实例生成 随机遮蔽 输出 结果一览 预训练源码结构简介 关于BERT,简单来说,它是一个基于Transfo ...
- Gin源码解析和例子——中间件(middleware)
在<Gin源码解析和例子--路由>一文中,我们已经初识中间件.本文将继续探讨这个技术.(转载请指明出于breaksoftware的csdn博客) Gin的中间件,本质是一个匿名回调函数.这 ...
- Colly源码解析——结合例子分析底层实现
通过<Colly源码解析--框架>分析,我们可以知道Colly执行的主要流程.本文将结合http://go-colly.org上的例子分析一些高级设置的底层实现.(转载请指明出于break ...
最新文章
- ORB特征提取策略对ORB-SLAM2性能的影响
- 【Ubuntu入门到精通系列讲解】常用其他命令(find ln tar apt)等速查
- webApp之meta标签
- c语言 如何创建adt_C语言探索之旅 | 第二部分第六课:创建你自己的变量类型
- 学习JS的正则表达式
- Spring @Aspect切面参数传递
- 线性代数及其应用(part3)--对角化
- ASP.NET Core on K8S学习初探(1)
- IntelliJ IDEA 单行注释调整
- 【操作系统】内存的分页管理与分段管理の异同
- Linux 下 -bash: mysql: command not found解决办法
- 【TensorFlow】TensorFlow从浅入深系列之二 -- 教你通过思维导图深度理解深层神经网络
- 新疆哈巴河冰雪旅游节开幕 游人沉醉雪舞冰封“第一桦”
- Ubuntu下安装VirtualBox和Android 安装到虚拟机中
- title()、upper()、lower()的用法
- P4782 【模板】2-SAT 问题
- typedef用法和结构体指针用法
- 《CSS权威指南》读书笔记3
- Windows远程桌面连接保姆级教学
- 简单的学生成绩录入查询系统
热门文章
- 一个单文件服务器(摘自《java网络编程》)
- office 论文 页码_还在花钱找人排版?这份最全攻略,让你论文一次过!
- java+log4j+是异步吗_log4j2用asyncRoot配置异步日志是如何使用disruptor
- 走心!15年程序员老兵的40条编程技巧,先收藏了!
- linux命令we,Linux 命令执行过程
- python 教材 配套 试题库_Python语言应用2020满分完整版考 试题库大全
- 用matlab给图像加水印,大神,在MATLAB中将图像水印插入音频文件可否给我个具体的步骤啊!很着急​...
- tcp网络示例客户端端以及代码,演示
- python中装饰函数的使用:
- 帆软扩展单元格运算的相关应用