1. 使用环境和特点
    setValue()只能在主线程中调用:多次调用每次都会收到
    postValue()可以在任何线程中调用:多次调用,只会收到最后一条更新(当然是在上一条没有发送之前,又收到一条消息时,前一条会被覆盖)

  2. 方法分析
    setValue()
    看官方如何介绍这个方法。

 /*** Sets the value. If there are active observers, the value will be dispatched to them.* <p>* This method must be called from the main thread. If you need set a value from a background* thread, you can use {@link #postValue(Object)}** @param value The new value*/@MainThreadprotected void setValue(T value)

上面的注释已经很清楚了:

这个方法必须在主线程中调用,如果你需要在后台线程中设置value,请移步 #postValue(Object)

  /*** Sets the value. If there are active observers, the value will be dispatched to them.* <p>* This method must be called from the main thread. If you need set a value from a background* thread, you can use {@link #postValue(Object)}** @param value The new value*/@MainThreadprotected void setValue(T value) {assertMainThread("setValue");mVersion++;mData = value;dispatchingValue(null);}static void assertMainThread(String methodName) {if (!ArchTaskExecutor.getInstance().isMainThread()) {throw new IllegalStateException("Cannot invoke " + methodName + " on a background"+ " thread");}}
  1. 首先调用 assertMainThread() 方法来判断当前线程是否为主线程(这里他通过一个ArchTaskExecutor的单例类来实现),如果不是主线程,直接抛异常
  2. 如果是在主线程中调用该方法,mVersion 加1,说明值发生了变化。
  3. 再把新的值保存起来。
  4. 更新value

postValue
官方对postValue()的介绍:

/*** Posts a task to a main thread to set the given value. So if you have a following code* executed in the main thread:* <pre class="prettyprint">* liveData.postValue("a");* liveData.setValue("b");* </pre>* The value "b" would be set at first and later the main thread would override it with* the value "a".* <p>* If you called this method multiple times before a main thread executed a posted task, only* the last value would be dispatched.** @param value The new value*/protected void postValue(T value)
/*** Posts a task to a main thread to set the given value. So if you have a following code* executed in the main thread:* <pre class="prettyprint">* liveData.postValue("a");* liveData.setValue("b");* </pre>* The value "b" would be set at first and later the main thread would override it with* the value "a".* <p>* If you called this method multiple times before a main thread executed a posted task, only* the last value would be dispatched.** @param value The new value*/
protected void postValue(T value) {boolean postTask;synchronized (mDataLock) {postTask = mPendingData == NOT_SET;mPendingData = value;}if (!postTask) {return;}ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
  1. 定义一个 postTask 的布尔值,判断是否要更新。
  2. 加同步锁,因为可能存在多个子线程同时调用 postValue() 的情况。
  3. 通过判断更新的值是否发生变化来对postTask赋值,并且将value赋值给 mPendingData(mPendingData == NOT_SET第一次一定是返回true,之后都是返回false,然后到这个值更新完毕之前的一瞬间会调用mPendingData=NOT_SET,这也是为什么多次调用 postValue()只有最后一个值才有效的原因)。
  4. 通过ArchTaskExecutor进行更新,通过方法及参数名字,我们可以猜测这一步干了什么事情:ArchTaskExecutor将一个Runnable对象往主线程里执行,那么mPostValueRunnable执行的环境一定是主线程,接下来我们再看看mPostValueRunnable究竟做了些什么。
   private final Runnable mPostValueRunnable = new Runnable() {@SuppressWarnings("unchecked")@Overridepublic void run() {Object newValue;synchronized (mDataLock) {newValue = mPendingData;mPendingData = NOT_SET;}setValue((T) newValue);}};//因为现在线程已经切换到主线程了,所以他直接就是调用 setValue()

翻译过来就是:

通过任务(Runnable)的方式在主线程中更新数据。
如果同时调用 .postValue(“a”)和.setValue(“b”),一定是值b被值a覆盖。
如果多次调用 .postValue(),只有最后一个值能够被分发(onChanged()被调用)。

最后
文中有几次出现了ArchTaskExecutor这个东西,这个类其实就是postValue切换至主线程更新的关键它具体的源码实现非常简单,直接是利用了Handler的机制。

 ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);......ArchTaskExecutor.........@Overridepublic void postToMainThread(Runnable runnable) {mDelegate.postToMainThread(runnable);}......DefaultTaskExecutor.........@Overridepublic void postToMainThread(Runnable runnable) {if (mMainHandler == null) {synchronized (mLock) {if (mMainHandler == null) {mMainHandler = createAsync(Looper.getMainLooper());}}}//noinspection ConstantConditionsmMainHandler.post(runnable);}

LiveData的postValue与setValue多次调用问题相关推荐

  1. LiveData的postValue丢值?setValue也丢值?

    废话少说,少说废话.先上四个例子: 1.在onCreate中 for循环调用postValue class MainActivity : AppCompatActivity() {private la ...

  2. LiveData ViewModel 使用详解

    什么是 LiveData LiveData 是一个可观测的数据持有类,但是不同于通常的被观察者,LiveData 具有生命周期感知能力.通俗点说,LiveData 就是具有 "Live&qu ...

  3. LiveData的使用和原理

    一.LiveData的基本使用 //创建一个LiveData对象 private val livedata = MutableLiveData<String>();//为LiveData设 ...

  4. LiveData实践

    LiveData的优点(摘自https://blog.csdn.net/m0_37778101/article/details/103789862) UI和实时数据保持一致,因为LiveData采用的 ...

  5. LiveData原理解析

    什么是LiveData LiveData是Android Architecture Components 其中的一个组件.主要用于更新UI数据和组件之间传值. 1.LiveData是一种持有可被观察数 ...

  6. LiveData+Room

    文章目录 LiveData 1.LiveData的作用 2.LiveData的特点 3.LiveData与ViewModel(无参数)的结合 4.LiveData与ViewModel(有参数)的结合 ...

  7. Android LiveData Observer 多次调用

    使用 Android Architecture Components,出现一个问题,LiveData的观察者Obsever会被多次调用. 我的写法是 private void loadData(Fra ...

  8. LiveData使用和生命感知原理

    你知道LiveData是如何做到感知生命周期的吗? 前言 使用LiveData有以下优势 数据及时刷新:无论前台任务还是后台任务,只要当前页面处于活跃状态,就能马上刷新数据 不会因 Activity ...

  9. Android Jetpack组件之 LiveData使用-源码

    1.前言 最近简单看了下google推出的框架Jetpack,感觉此框架的内容可以对平时的开发有很大的帮助,也可以解决很多开发中的问题,对代码的逻辑和UI界面实现深层解耦,打造数据驱动型UI界面. A ...

  10. Android架构组件LiveData+ViewModel

    前言 最近项目中有用到LiveData+ViewModel的架构组件,今天来学习一波.本篇文章参考:MVVM 架构,ViewModel和LiveData 所有语言为Kotlin. LiveData L ...

最新文章

  1. JAVA中 @Override 的作用
  2. hdu1506 dp
  3. linux下json数据解析,Linux下使用jq简单解析json的方法
  4. 数据统计 测试方法_统计测试:了解如何为数据选择最佳测试!
  5. python的while循环时if不能打印_Python if语句在while循环中没有响应
  6. Maven(2)--- 环境配置
  7. 车座自动排水阀行业调研报告 - 市场现状分析与发展前景预测(2021-2027年)
  8. 外包软件开发时要避免的五个陷阱
  9. python中模块下载方法(conda+pip)
  10. linux无线电工具grax,开源软件无线电GNU Radio
  11. udp端口转发 Linux,Linux iptables 端口转发
  12. 微信聊天记录删除了怎么恢复
  13. 解决缓存和数据库双写数据一致性问题
  14. STM32cubemx教程及STM32入门(四)串口通信
  15. 关于报错:There is already ‘什么Controller‘ bean method的解决方法
  16. CH341应用升级为CH347软硬件注意事项
  17. React-Native强制关闭软键盘
  18. 房地产开发商崩盘样本:楼盘捂了两年,欠40亿巨债
  19. 开发一个App来为你的女神“化妆”!
  20. iOS开发者账号的区别

热门文章

  1. 网站速度优化4个实用办法
  2. phpstudy开机自启
  3. 安卓flash插件_谷歌Chrome 76稳定版正式发布:默认禁用Flash
  4. matlab二次曲线插补,圆弧插补器插补非圆二次曲线的方法
  5. 软考高级系统架构师论文,到底该如何写
  6. mysql跨库查询数据
  7. [Python]更改图片底色
  8. 用给定的key对字符串进行sha256加密-postman预处理
  9. Django验证码*异步方案Celery之Celery介绍和使用(Celery介绍、创建Celery实例并加载配置、加载Celery配置、定义发送短信任务、启动Celery服务、调用发送短信任务)
  10. 第九节 html特殊文字符号