LiveData 机制详解
一.消息监听机制
来个例子
data.observe(this, observer)data.setValue(1)
上述代码,监听者会触发一次,我们来看看其中的缘由
在setValue里会给mVersion 成员变量加一,意味着数据的版本 加一,这个mVersion默认值是-1
mVersion++;mData = value;dispatchingValue(null);
然后追查dispatchingValue函数的调用链,看它 是如何通知到监听者, 因为当初传的是空,所以会执行else语句
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());}}
看看mObservers是什么,在 oberser函数里,把监听者和生命周期持有者封装存放在mObservers,所以遍历它来给所有注册的监听者传递最新的数据
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
这个considerNotify里,监听者有一个mLastVersion 成员变量,默认值是-1,与LiveData的mVersion相比较,如果大于等于mVersion,就表示数据版本更新,无需触发监听,否则就是把mVersion赋值给mLastVersion, 并且触发监听。
if (observer.mLastVersion >= mVersion) {return;}observer.mLastVersion = mVersion;observer.mObserver.onChanged((T) mData);
二.粘性消息机制
首先展示一个最简单能体现粘性消息的例子
data.setValue(1)data.observe(this, observer)
上述代码依旧 能够触发监听者的回调,我们看看observe函数做了什么,把监听者 并和lifecycle持有者一起打包
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);owner.getLifecycle().addObserver(wrapper);
找找 getLifecycle()获取的实例,我们需要从AppCompatActivity开始找,最后在FragmentActivity找到
final LifecycleRegistry mFragmentLifecycleRegistry = new LifecycleRegistry(this);
然后来看看它的addObserver函数,它调用了这么一行代码,用于传递事件,继续追查
statefulObserver.dispatchEvent(lifecycleOwner, upEvent(statefulObserver.mState));
给 封装了lifecycle持有者发送数据,看 mLifecycleObserver实例在哪
mLifecycleObserver.onStateChanged(owner, event);
得继续 看 lifecycleEventObserver
ObserverWithState(LifecycleObserver observer, State initialState) {mLifecycleObserver = Lifecycling.lifecycleEventObserver(observer);mState = initialState;}
这个判断很多,我 们需要 清楚这个observer的实例是啥
class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver
public interface GenericLifecycleObserver extends LifecycleEventObserver
好了,我们再来看看lifecycleEventObserver 函数,说白了就是返回传进去的 实例了
boolean isLifecycleEventObserver = object instanceof LifecycleEventObserver;if (isLifecycleEventObserver) {return (LifecycleEventObserver) object;}
然后看看onStateChanged函数调用了啥
activeStateChanged(shouldBeActive());
继续
dispatchingValue(this);
还继续,这个函数就很眼熟了,里面进行了版本比较,和触发更新,
considerNotify(initiator);
三.setValue
首先说说setValue,它的元注解MainThread规定了此函数在主线程执行,赋值时,版本加一
@MainThreadprotected void setValue(T value) {assertMainThread("setValue");mVersion++;mData = value;dispatchingValue(null);}
我再给出一个使用的例子,你们 猜猜,触发监听多少次,结果是一次,为何,我们接着看看 dispatchingValue函数
override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)Log.v("zzw","onCreate")data.observe(this, observer)data.setValue(1)data.setValue(2)}
dispatchingValue最后会执行 considerNotify函数,这个函数虽然我之前贴出过几次,但没有说到它真正的厉害之处。
首先需要提醒的是 LiveData不只是一个简单的被监听者,它依赖于生命周期。
我在 if(!observer.mActive)这里打了断电,第一次 mActive为false,第二次为false,第三次为true。我调用了 两次setValue,为何有 三次调用到这里,说明还有其他 地方调用了。
private void considerNotify(ObserverWrapper observer) {if (!observer.mActive) {return;}if (!observer.shouldBeActive()) {observer.activeStateChanged(false);return;}if (observer.mLastVersion >= mVersion) {return;}observer.mLastVersion = mVersion;//noinspection uncheckedobserver.mObserver.onChanged((T) mData);}
这里我对onStart和onResume都复写,打日志,再运行一次。这个说明第三次是在 onStart和onResume之间
onCreate
onStart
2
onResume
那我把 setvalue的代码放在onStart里,结果一样,如果放在onResume里,成功
onCreate
onStart
onResume
1
2
这里我再次打断点,considerNotify调用了三次,而且第一次因为LiveData的版本是-1,所以没有更新 数据。那这个多出的
一次调用是在onResume的开头。
首先我们看看,我们 在onStart和onCreate里的considerNotify调用是如何被中断的。因为前面打过断点,是因为observer.mActive为false,而这个变量默认没有赋值,也就是false,找找这个observer的 来源,来源是 LiveData.observer函数
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
这个observer的类是LifecycleBoundObserve,他有一个函数,看起来是分发状态,并且调用了父类的函数
@Overridepublic void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {removeObserver(mObserver);return;}activeStateChanged(shouldBeActive());}
这里可以看出 mActive的值由传入的newActive决定,也就是 shouldBeActive函数决定
void activeStateChanged(boolean newActive) {if (newActive == mActive) {return;}mActive = newActive;if (mActive) {dispatchingValue(this);}}
这个shouldBeActive函数实质内容就是, 判断当前宿主的生命周期是否大于等于 onStart,如果 是的就返回true
@Overrideboolean shouldBeActive() {return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);}
所以我们之前的数据 传不到 监听者,是因为生命 周期不到。而每次生命周期变化,都会触发 onStateChanged函数
mLifecycleObserver.onStateChanged(owner, event);
setValue的总结:值传递到监听者,有生命周期的限制(onStart以上,onDestroy以下)并且每次生命周期变化都会试着将值传递给监听者。
四.postValue
postValue与setValue最大的 不同是,它可以在子线程传递数据。
而在子线程之间共享数据,最大的问题是线程同步,防止出现脏数据的问题
首先看看postValue,在同步锁下它先把 值传给 mPendingData,如果我们是连调用几个postValue, 因为当前mPendingData已经被赋值了,所以就被return了,看看 postToMainThread做了啥
protected void postValue(T value) {boolean postTask;synchronized (mDataLock) {postTask = mPendingData == NOT_SET;mPendingData = value;}if (!postTask) {return;}ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);}
因为这是一个代理模式,我找找他的实现类
private ArchTaskExecutor() {mDefaultTaskExecutor = new DefaultTaskExecutor();mDelegate = mDefaultTaskExecutor;}
使用创建了一个在主线程运行的Handler,来运行runable
@Overridepublic void postToMainThread(Runnable runnable) {if (mMainHandler == null) {synchronized (mLock) {if (mMainHandler == null) {mMainHandler = new Handler(Looper.getMainLooper());}}}//noinspection ConstantConditionsmMainHandler.post(runnable);}
我们再回个头看看,运行的runable的内容,它把mPendingdata的值取出,然后赋予默认值,然后调用setValue。 这里需要 特别说明的是,之前也说过 连续调用几次postvalue, 只有第一次调用会 发送这个Runnable,但是这个 mPendingdata每次都会被赋值,所以这个节约了刷新次数。
private final Runnable mPostValueRunnable = new Runnable() {@Overridepublic void run() {Object newValue;synchronized (mDataLock) {newValue = mPendingData;mPendingData = NOT_SET;}//noinspection uncheckedsetValue((T) newValue);}};
五.特殊情况解决
1.如果想让连续多次调用setValue,每次都触发更新,需要在onResume函数里调用
2.如果不想让分发LiveData设置的初始值,建议在设置初始值前,添加观察者
LiveData 机制详解相关推荐
- PHP autoload机制详解
PHP autoload机制详解 转载自 jeakccc PHP autoload机制详解 (1) autoload机制概述 在使用PHP的OO模式开发系统时,通常大家习惯上将每个类的实现都存放在一个 ...
- 模糊匹配 读音_onenote搜索机制详解②:两种搜索模式,模糊与精确匹配
先从纯文本搜索讲起,这是最基本也是最重要的. 从这篇开始,以及接下来连续几篇文章,都会介绍搜索的基础功能.注意,这几篇文章中谈论的都是基本的.正常的搜索功能,暂时不考虑Bug等因素. 在很多软件(例如 ...
- Java类加载机制详解【java面试题】
Java类加载机制详解[java面试题] (1)问题分析: Class文件由类装载器装载后,在JVM中将形成一份描述Class结构的元信息对象,通过该元信息对象可以获知Class的结构信息:如构造函数 ...
- Numpy的广播机制详解(broadcasting)
Numpy的广播机制详解(broadcasting) 广播(Broadcast)是 numpy 对不同形状(shape)的数组进行数值计算的方式, 对数组的算术运算通常在相应的元素上进行. 如果两个数 ...
- Session机制详解及分布式中Session共享解决方案
Session机制详解及分布式中Session共享解决方案 参考文章: (1)Session机制详解及分布式中Session共享解决方案 (2)https://www.cnblogs.com/jing ...
- java异常处理机制详解
java异常处理机制详解 参考文章: (1)java异常处理机制详解 (2)https://www.cnblogs.com/vaejava/articles/6668809.html 备忘一下.
- SpringMVC异常处理机制详解[附带源码分析]
SpringMVC异常处理机制详解[附带源码分析] 参考文章: (1)SpringMVC异常处理机制详解[附带源码分析] (2)https://www.cnblogs.com/fangjian0423 ...
- 动态代理机制详解(JDK 和CGLIB,Javassist,ASM)
2019独角兽企业重金招聘Python工程师标准>>> 在运行时期可以按照Java虚拟机规范对class文件的组织规则生成对应的二进制字节码.当前有很多开源框架可以完成这些功能,如A ...
- JAVA之JVM垃圾回收(GC)机制详解
一.为什么需要垃圾回收 如果不进行垃圾回收,内存迟早都会被消耗空,因为我们在不断的分配内存空间而不进行回收.除非内存无限大,我们可以任性的分配而不回收,但是事实并非如此.所以,垃圾回收是必须的. 二. ...
最新文章
- js中Blob对象一般用法
- 电脑动态屏保_8款电脑软件,每一款都能让你的电脑更好用
- ElasticSearch各种查询对象Query的使用
- Windows高级编程学习笔记(一)
- 【转】20个让Web Developer开发生涯更加轻松的工具
- ORB-SLAM3论文解读
- [C#] TestHttpPost:测试Http的POST方法的小工具
- 华为交换机将端口由trunk更改为access报错解决方法
- JS 把 Wed Jul 15 2015 00:00:00 GMT+0800 转换成2015-07-15
- 【业务安全02】业务数据安全
- 软考2022下半年上午题真题和知识点整理
- matlab 正交多项式,常用正交多项式
- 【微信小程序源码】独立版云贝餐饮连锁V2_2.3.9源码线传小程序,新增堂食订单,支付打印新增下单时间显示
- JDP02-[策略模式]-鸭子模型
- Docker基础: Linux内核之Cgroups(1)
- 知觉:看到什么就是什么
- App开发中适用的短信SDK
- emoji表情在web html上显示
- 43、基于51单片机电子称16按键LCD 1602显示系统设计
- 【ML】基于机器学习的房价预测研究(系列7:双向LSTM模型)