基于: macOs:10.14/AS:3.4/Android build-tools:28.0.0

思路

看源码前先考虑下如果要自己实现 LiveData 应该怎么做?

基本做法:

  1. 目标数据私有;
  2. 开放 setter 方法用于更新目标数据;
  3. 提供方法添加数据变化监听器(Observer);

扩展:

  1. 允许子线程更新数据, 因此 setter 需要考虑同步;
  2. 项目中可能多个地方需要用到目标数据,因此回调监听器可以添加多个;
  3. 数据变化时常常都需要更新UI,而UI有生命周期,因此 Observer 需要提供 Lifecycle 相关逻辑支持,包括:
    1. 定义处于哪些生命周期的 Observer 可以收到数据更新;
    2. onDestroy() 时自动移除 Observer 等;
  4. 如何定义 数据变化 呢? 最简单直接的做法是每次触发 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 只是简单重写了 LiveDatasetValue(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);}
}
复制代码

小结

  1. 只能在主线程中进行 Observer 的添加:

    1. observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer)
    2. observeForever(@NonNull Observer<T> observer)
  2. 添加带 LifecycleOwnerObserver 时, 若发生 onDestory() ,则会自动移除 Observer;
  3. 数据只会在 LifecycleOwner 处于 onStart()/onResume()/onPause() 生命周期时,才会分发;
  4. 若处于 active 的 Observer 数量从 1 -> 0, 回调 onInactive() ,适用于子类进行资源释放;
  5. 若处于 active 的 Observer 数量从 0 -> 1, 回调 onActive();
  6. LiveData 类和 ObserverWrapper 类都会在内部持有一个数据版本号;
  7. LiveData 数据发生变化时,会切换到主线程,然后遍历所有 Observer, 并将数据分发给处于 active 状态并且数据版本号不一致的 Observer;

转载于:https://juejin.im/post/5cd907166fb9a031ef63d66c

LiveData源码解析相关推荐

  1. LiveData 源码解析(2.4.1 版本)

    文章目录 1.LiveData 简介 2.LiveData 配置与基本用法 2.1 依赖引入与配置 2.2 基本用法 2.2.1 LiveData 简单使用 2.2.2 LiveData 扩展 2.2 ...

  2. Android Jetpack LiveData 源码解析

    是什么 LiveData 是具备生命周期的数据,当数据放生变化的时候,如果页面已经销毁,那么就不会回调给监听者. 有什么用? 当我们获取到网络请求的数据,如果页面已经销毁了,就不会调用更新Ui 的方法 ...

  3. Lifecycle 源码解析(2.4.1 版本)

    文章目录 1.Lifecycle 简介 2.Lifecycle 配置与基本用法 2.1 依赖引入与配置 2.2 基本用法 2.2.1 Lifecycle 简单使用 2.2.2 普通 Activity ...

  4. ViewModel 源码解析

    MVVM架构中,会用到ViewModel类,那么这个类原理是什么呢?有什么好处呢? 第一部分:源码文档解析 /*** ViewModel is a class that is responsible ...

  5. 5. Jetpack源码解析---ViewModel基本使用及源码解析

    截止到目前为止,JetpackNote源码分析的文章已经有四篇文章了,这一系列的文章我的初衷是想仔细研究一下Jetpack,最终使用Jetpack组件写一个Demo,上一篇已经分析了LiveData, ...

  6. 谷歌BERT预训练源码解析(二):模型构建

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/weixin_39470744/arti ...

  7. 谷歌BERT预训练源码解析(三):训练过程

    目录 前言 源码解析 主函数 自定义模型 遮蔽词预测 下一句预测 规范化数据集 前言 本部分介绍BERT训练过程,BERT模型训练过程是在自己的TPU上进行的,这部分我没做过研究所以不做深入探讨.BE ...

  8. 谷歌BERT预训练源码解析(一):训练数据生成

    目录 预训练源码结构简介 输入输出 源码解析 参数 主函数 创建训练实例 下一句预测&实例生成 随机遮蔽 输出 结果一览 预训练源码结构简介 关于BERT,简单来说,它是一个基于Transfo ...

  9. Gin源码解析和例子——中间件(middleware)

    在<Gin源码解析和例子--路由>一文中,我们已经初识中间件.本文将继续探讨这个技术.(转载请指明出于breaksoftware的csdn博客) Gin的中间件,本质是一个匿名回调函数.这 ...

  10. Colly源码解析——结合例子分析底层实现

    通过<Colly源码解析--框架>分析,我们可以知道Colly执行的主要流程.本文将结合http://go-colly.org上的例子分析一些高级设置的底层实现.(转载请指明出于break ...

最新文章

  1. ORB特征提取策略对ORB-SLAM2性能的影响
  2. 【Ubuntu入门到精通系列讲解】常用其他命令(find ln tar apt)等速查
  3. webApp之meta标签
  4. c语言 如何创建adt_C语言探索之旅 | 第二部分第六课:创建你自己的变量类型
  5. 学习JS的正则表达式
  6. Spring @Aspect切面参数传递
  7. 线性代数及其应用(part3)--对角化
  8. ASP.NET Core on K8S学习初探(1)
  9. IntelliJ IDEA 单行注释调整
  10. 【操作系统】内存的分页管理与分段管理の异同
  11. Linux 下 -bash: mysql: command not found解决办法
  12. 【TensorFlow】TensorFlow从浅入深系列之二 -- 教你通过思维导图深度理解深层神经网络
  13. 新疆哈巴河冰雪旅游节开幕 游人沉醉雪舞冰封“第一桦”
  14. Ubuntu下安装VirtualBox和Android 安装到虚拟机中
  15. title()、upper()、lower()的用法
  16. P4782 【模板】2-SAT 问题
  17. typedef用法和结构体指针用法
  18. 《CSS权威指南》读书笔记3
  19. Windows远程桌面连接保姆级教学
  20. 简单的学生成绩录入查询系统

热门文章

  1. 一个单文件服务器(摘自《java网络编程》)
  2. office 论文 页码_还在花钱找人排版?这份最全攻略,让你论文一次过!
  3. java+log4j+是异步吗_log4j2用asyncRoot配置异步日志是如何使用disruptor
  4. 走心!15年程序员老兵的40条编程技巧,先收藏了!
  5. linux命令we,Linux 命令执行过程
  6. python 教材 配套 试题库_Python语言应用2020满分完整版考 试题库大全
  7. 用matlab给图像加水印,大神,在MATLAB中将图像水印插入音频文件可否给我个具体的步骤啊!很着急​...
  8. tcp网络示例客户端端以及代码,演示
  9. python中装饰函数的使用:
  10. 帆软扩展单元格运算的相关应用