一文读懂LiveData 粘性事件
一文读懂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 粘性事件相关推荐
- java响应鼠标滚轮事件_一文读懂鼠标滚轮事件(wheelEvent)
最近在用VUE写一个后台管理系统,顶部标签页涉及鼠标滚轮事件,由于每个浏览器对滚轮事件的处理方式不一样,个人对这个又不懂,折腾了很久,参考了大神的代码,也把百度翻烂了,找到了一篇陈旧的博文(其实是主题 ...
- 一文读懂Android View事件分发机制
Android View 虽然不是四大组件,但其并不比四大组件的地位低.而View的核心知识点事件分发机制则是不少刚入门同学的拦路虎.ScrollView嵌套RecyclerView(或者ListVi ...
- 一文读懂SpringBoot中的事件机制
一文读懂SpringBoot中的事件机制?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法. 要"监听"事件,我们总是 ...
- C_一文读懂推荐系统知识体系-上(概念、结构、算法)
本文主要阐述: 推荐系统的3个W 推荐系统的结构 推荐引擎算法 浏览后四章的内容请见下篇. 1. 推荐系统的3个W 1.1 是什么(What is it?) 推荐系统就是根据用户的历史行为.社交关系. ...
- 你真的懂数据分析吗?一文读懂数据分析的流程、基本方法和实践
导读:无论你的工作内容是什么,掌握一定的数据分析能力,都可以帮你更好的认识世界,更好的提升工作效率.数据分析除了包含传统意义上的统计分析之外,也包含寻找有效特征.进行机器学习建模的过程,以及探索数据价 ...
- 从根上理解高性能、高并发(七):深入操作系统,一文读懂进程、线程、协程
本文引用了"一文读懂什么是进程.线程.协程"一文的主要内容,感谢原作者的无私分享. 1.系列文章引言 1.1 文章目的 作为即时通讯技术的开发者来说,高性能.高并发相关的技术概念早 ...
- 腾讯资深架构师干货总结:一文读懂大型分布式系统设计的方方面面
1.引言 我们常常会听说,某个互联网应用的服务器端系统多么牛逼,比如QQ.微信.淘宝.那么,一个大型互联网应用的服务器端系统,到底牛逼在什么地方?为什么海量的用户访问,会让一个服务器端系统变得更复杂? ...
- 一文读懂:本地数据湖丨数据仓库丨云数据湖的利与弊
数据湖指的是一个中心位置,大量数据以原始的.非结构化的格式存储,其中包含有关数据和惟一标识符的信息.它们存储的数据可以稍后进行处理,以提取有价值的业务见解并推动业务向前发展. 这种类型的灵活组织允许存 ...
- 一文读懂NLP之隐马尔科夫模型(HMM)详解加python实现
一文读懂NLP之隐马尔科夫模型(HMM)详解加python实现 1 隐马尔科夫模型 1.1 HMM解决的问题 1.2 HMM模型的定义 1.2.1HMM的两个假设 1.2.2 HMM模型 1.3 HM ...
- 一文读懂贝叶斯原理(Bayes‘ theorem)
一文读懂贝叶斯原理(Bayes' theorem) 前言:贝叶斯定理是18世纪英国数学家托马斯·贝叶斯(Thomas Bayes)提出得重要概率论理论.以下摘一段 wikipedia 上的简介: 一. ...
最新文章
- 第十、十一周项目四 - 教师兼干部类
- Spring Boot @ControllerAdvice 处理全局异常,返回固定格式Json
- Java_Web--JDBC 增加记录操作模板
- 分布式devops_维护分布式团队的DevOps心态的10个技巧
- Java成神之路——UML类关系图
- oracle pk_serial,Oracle 常用技巧和脚本-数据库专栏,ORACLE
- redis运行状态图形化监控工具 — RedisLive
- 关于 Google“博客搜索”Ping 服务应用编程接口(API)
- php开发oa系统的插件下载不了,OA系统安装不了office控件的解决方法
- win7打开计算机死机,win7系统进入桌面总是死机或者卡死怎么办
- IOS苹果账号三方登录服务器端验证
- Clustering by Passing Messages Between Data Points
- Mongo客户端【Studio 3T】免费激活方式
- wear手表软件合集_如何找出正在使用Android Wear手表电池的电池
- python实现zigzag_Zigzag Iterator的Pythonic方式?
- 试题 B: 顺子日期
- [附源码]Python计算机毕业设计Django飞越青少儿兴趣培训机构管理系统
- 影院购票系统 C#源代码
- 一款简洁实用电脑屏幕录制工具
- 用蓝牙传照片到电脑的一个不务正业的下午
热门文章
- jdk8特性 lambda表达式
- Logistic逻辑回归预测员工离职问题
- 微信企业号上传图片 php,C#开发微信门户及应用微信企业号的消息发送(文本、图片、文件、语音、视频、图文消息等)...
- linux基础教程 ppt,Linux基础教程(1)操作系统基础 PPT
- 【英语:语法基础】B2.核心语法-动词
- python矩阵教程_Python Numpy Tutorial / Python Numpy 教程 (矩阵和图像操作)
- 手把手教你如何在Innovus中解决local congestion问题
- Pr 入门教程:如何使用项目面板?
- 阿里云CDN介绍以及如何配合OSS使用
- 学习Android闹钟源代码(三)-AlarmClock类分析(part2)