一文读懂LiveData 的粘性事件

前言

说的通俗一点,就是先发送数据,后订阅,也可以接收到数据。

这其实本是livedata 的一个特性,但是却给我们的日常使用带来了非常的不便,而且不提供API来解除粘性事件,这种做法确实不是很友好。

接下来,就带大家来揭秘一下LiveData 粘性事件的原理。

前方大量源码来袭,如有不适者,可以直接跳总结。

原理

首先我们从发送消息开始

liveData.postValue("页面1 发送的消息")

发送消息有两个方法:setValue和postValue

setValue 只能在主线程使用,postValue可以在任何线程使用,它被调用时,通过handler切换到主线程,再调用 setValue

    @MainThreadprotected void setValue(T value) {assertMainThread("setValue");mVersion++;mData = value;dispatchingValue(null);}

这里有个 mVersion 要注意一下,后面会用到。然后就是通过 dispatchingValue 方法来分发消息了。

    void dispatchingValue(@Nullable ObserverWrapper initiator) {if (mDispatchingValue) {mDispatchInvalidated = true;return;}mDispatchingValue = true;do {mDispatchInvalidated = false;if (initiator != null) {considerNotify(initiator);initiator = null;} else {for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {considerNotify(iterator.next().getValue());if (mDispatchInvalidated) {break;}}}} while (mDispatchInvalidated);mDispatchingValue = false;}

在这个方法里,主要是参数传的观察者是否为空,如果不为空,则向此观察者分发消息,如果为空,将会从观察者集合里面遍历观察者,进行分发。在这里,我们主要看 considerNotify 方法。

    private void considerNotify(ObserverWrapper observer) {...............if (observer.mLastVersion >= mVersion) {return;}observer.mLastVersion = mVersion;observer.mObserver.onChanged((T) mData);}

在我们前面提到 mVersion 用到了这里,和mLastVersion 做了比较,这点我们在下个步骤进行说明。

这就是我们全部发送消息的过程了,很简单明了,但是还不足以窥全貌,接下来我们分析另外一个步骤,监听。

liveData.observe(this) {Log.e("TAG", "onCreate: ")tv.setText("监听到的消息:$it")}
    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {assertMainThread("observe");if (owner.getLifecycle().getCurrentState() == DESTROYED) {// ignorereturn;}LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);............owner.getLifecycle().addObserver(wrapper);}

在这里,主要是对我们的 owner 和observer 做了一层包装,然后让 lifecycle 进行了监听。然后我们就看看 包装了点什么

    class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {@NonNullfinal LifecycleOwner mOwner;LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {super(observer);mOwner = owner;}.........@Overridepublic void onStateChanged(@NonNull LifecycleOwner source,@NonNull Lifecycle.Event event) {Lifecycle.State currentState = mOwner.getLifecycle().getCurrentState();if (currentState == DESTROYED) {removeObserver(mObserver);return;}Lifecycle.State prevState = null;while (prevState != currentState) {prevState = currentState;activeStateChanged(shouldBeActive());currentState = mOwner.getLifecycle().getCurrentState();}}............}

可以看到 LifecycleBoundObserver 继承了 ObserverWrapper ,实现了 LifecycleEventObserver 接口。

LifecycleEventObserver 接口 主要是当 lifecycle 状态改变的时候会感应到,并进行回调。

然后我们主要看看父类 ObserverWrapper :

    private abstract class ObserverWrapper {final Observer<? super T> mObserver;boolean mActive;int mLastVersion = START_VERSION;ObserverWrapper(Observer<? super T> observer) {mObserver = observer;}............void activeStateChanged(boolean newActive) {if (newActive == mActive) {return;}// immediately set active state, so we'd never dispatch anything to inactive// ownermActive = newActive;changeActiveCounter(mActive ? 1 : -1);if (mActive) {dispatchingValue(this);}}}

是不是看到了一个熟悉的面孔,就是我们上个步骤 提到的 mLastVersion ,它是在这里定义的,并且默认是-1;这里会在后文进行贯穿起来,先了解它的源头。

接下来,我们先继续走流程,还是LifecycleBoundObserver 类中,当状态改变的时候,会调用 onStateChanged 方法

  @Overridepublic void onStateChanged(@NonNull LifecycleOwner source,@NonNull Lifecycle.Event event) {Lifecycle.State currentState = mOwner.getLifecycle().getCurrentState();if (currentState == DESTROYED) {removeObserver(mObserver);return;}Lifecycle.State prevState = null;while (prevState != currentState) {prevState = currentState;activeStateChanged(shouldBeActive());currentState = mOwner.getLifecycle().getCurrentState();}}

当活跃状态改变的时候,会 调用 activeStateChanged :

void activeStateChanged(boolean newActive) {if (newActive == mActive) {return;}mActive = newActive;changeActiveCounter(mActive ? 1 : -1);if (mActive) {dispatchingValue(this);}
}

当状态是活跃状态的时候,会调用 dispatchingValue 进行数据分发,我们上文用到的分发是遍历所有观察者进行数据分发,这次是只分发当前观察者。

总结

接下来我们进行连贯一下:

首先发送数据 postValue ,次数会让进行 mVersion++ 操作,然后遍历观察者进行分发。

然后是进行监听操作,在进行监听的时候,会使用LifecycleBoundObserver 对观察者进行包装一下,在这个操作里面,LifecycleBoundObserver 的父类 ObserverWrapper 定义了 mLastVersion 为-1 。在数据最后进行分发的时候,mLastVersion 是小于 mVersion 的,所以未拦截,然后进行了数据的分发。

然后就产生了粘性事件。

关于粘性事件的解决方案现在也有很多,这里就不做赘述 ,可以参考一下这篇文章:

https://www.jianshu.com/p/d0244c4c7cc9

一文读懂LiveData 粘性事件相关推荐

  1. java响应鼠标滚轮事件_一文读懂鼠标滚轮事件(wheelEvent)

    最近在用VUE写一个后台管理系统,顶部标签页涉及鼠标滚轮事件,由于每个浏览器对滚轮事件的处理方式不一样,个人对这个又不懂,折腾了很久,参考了大神的代码,也把百度翻烂了,找到了一篇陈旧的博文(其实是主题 ...

  2. 一文读懂Android View事件分发机制

    Android View 虽然不是四大组件,但其并不比四大组件的地位低.而View的核心知识点事件分发机制则是不少刚入门同学的拦路虎.ScrollView嵌套RecyclerView(或者ListVi ...

  3. 一文读懂SpringBoot中的事件机制

    一文读懂SpringBoot中的事件机制?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法. 要"监听"事件,我们总是 ...

  4. C_一文读懂推荐系统知识体系-上(概念、结构、算法)

    本文主要阐述: 推荐系统的3个W 推荐系统的结构 推荐引擎算法 浏览后四章的内容请见下篇. 1. 推荐系统的3个W 1.1 是什么(What is it?) 推荐系统就是根据用户的历史行为.社交关系. ...

  5. 你真的懂数据分析吗?一文读懂数据分析的流程、基本方法和实践

    导读:无论你的工作内容是什么,掌握一定的数据分析能力,都可以帮你更好的认识世界,更好的提升工作效率.数据分析除了包含传统意义上的统计分析之外,也包含寻找有效特征.进行机器学习建模的过程,以及探索数据价 ...

  6. 从根上理解高性能、高并发(七):深入操作系统,一文读懂进程、线程、协程

    本文引用了"一文读懂什么是进程.线程.协程"一文的主要内容,感谢原作者的无私分享. 1.系列文章引言 1.1 文章目的 作为即时通讯技术的开发者来说,高性能.高并发相关的技术概念早 ...

  7. 腾讯资深架构师干货总结:一文读懂大型分布式系统设计的方方面面

    1.引言 我们常常会听说,某个互联网应用的服务器端系统多么牛逼,比如QQ.微信.淘宝.那么,一个大型互联网应用的服务器端系统,到底牛逼在什么地方?为什么海量的用户访问,会让一个服务器端系统变得更复杂? ...

  8. 一文读懂:本地数据湖丨数据仓库丨云数据湖的利与弊

    数据湖指的是一个中心位置,大量数据以原始的.非结构化的格式存储,其中包含有关数据和惟一标识符的信息.它们存储的数据可以稍后进行处理,以提取有价值的业务见解并推动业务向前发展. 这种类型的灵活组织允许存 ...

  9. 一文读懂NLP之隐马尔科夫模型(HMM)详解加python实现

    一文读懂NLP之隐马尔科夫模型(HMM)详解加python实现 1 隐马尔科夫模型 1.1 HMM解决的问题 1.2 HMM模型的定义 1.2.1HMM的两个假设 1.2.2 HMM模型 1.3 HM ...

  10. 一文读懂贝叶斯原理(Bayes‘ theorem)

    一文读懂贝叶斯原理(Bayes' theorem) 前言:贝叶斯定理是18世纪英国数学家托马斯·贝叶斯(Thomas Bayes)提出得重要概率论理论.以下摘一段 wikipedia 上的简介: 一. ...

最新文章

  1. 第十、十一周项目四 - 教师兼干部类
  2. Spring Boot @ControllerAdvice 处理全局异常,返回固定格式Json
  3. Java_Web--JDBC 增加记录操作模板
  4. 分布式devops_维护分布式团队的DevOps心态的10个技巧
  5. Java成神之路——UML类关系图
  6. oracle pk_serial,Oracle 常用技巧和脚本-数据库专栏,ORACLE
  7. redis运行状态图形化监控工具 — RedisLive
  8. 关于 Google“博客搜索”Ping 服务应用编程接口(API)
  9. php开发oa系统的插件下载不了,OA系统安装不了office控件的解决方法
  10. win7打开计算机死机,win7系统进入桌面总是死机或者卡死怎么办
  11. IOS苹果账号三方登录服务器端验证
  12. Clustering by Passing Messages Between Data Points
  13. Mongo客户端【Studio 3T】免费激活方式
  14. wear手表软件合集_如何找出正在使用Android Wear手表电池的电池
  15. python实现zigzag_Zigzag Iterator的Pythonic方式?
  16. 试题 B: 顺子日期
  17. [附源码]Python计算机毕业设计Django飞越青少儿兴趣培训机构管理系统
  18. 影院购票系统 C#源代码
  19. 一款简洁实用电脑屏幕录制工具
  20. 用蓝牙传照片到电脑的一个不务正业的下午

热门文章

  1. jdk8特性 lambda表达式
  2. Logistic逻辑回归预测员工离职问题
  3. 微信企业号上传图片 php,C#开发微信门户及应用微信企业号的消息发送(文本、图片、文件、语音、视频、图文消息等)...
  4. linux基础教程 ppt,Linux基础教程(1)操作系统基础 PPT
  5. 【英语:语法基础】B2.核心语法-动词
  6. python矩阵教程_Python Numpy Tutorial / Python Numpy 教程 (矩阵和图像操作)
  7. 手把手教你如何在Innovus中解决local congestion问题
  8. Pr 入门教程:如何使用项目面板?
  9. 阿里云CDN介绍以及如何配合OSS使用
  10. 学习Android闹钟源代码(三)-AlarmClock类分析(part2)