废话少说,少说废话。先上四个例子:

1、在onCreate中 for循环调用postValue

class MainActivity : AppCompatActivity() {private lateinit var activityMainBinding: ActivityMainBindingprivate val liveData = MutableLiveData<Int>()override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)activityMainBinding = ActivityMainBinding.inflate(layoutInflater)setContentView(activityMainBinding.root)for (i in 0..2) {liveData.postValue(i)Log.d("MyMainActivity", "postValue: $i")}// 订阅观察者liveData.observe(this) {Log.d("MyMainActivity", "observer: $it")}}}

输出打印:

2022-08-15 10:38:28.269 D/MyMainActivity: postValue: 02022-08-15 10:38:28.269 D/MyMainActivity: postValue: 12022-08-15 10:38:28.269 D/MyMainActivity: postValue: 22022-08-15 10:38:28.297 D/MyMainActivity: observer: 2

可以显而易见的看到postValue发送0,1,2数据后,但只接收到了最后一次发送的数值2.

2、在onCreate中 for循环调用setValue

class MainActivity : AppCompatActivity() {private lateinit var activityMainBinding: ActivityMainBindingprivate val liveData = MutableLiveData<Int>()override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)activityMainBinding = ActivityMainBinding.inflate(layoutInflater)setContentView(activityMainBinding.root)for (i in 0..2) {liveData.value = iLog.d("MyMainActivity", "setValue: $i")}// 订阅观察者liveData.observe(this) {Log.d("MyMainActivity", "observer: $it")}}}

输出:

2022-08-15 10:48:57.072  D/MyMainActivity: setValue: 02022-08-15 10:48:57.072  D/MyMainActivity: setValue: 12022-08-15 10:48:57.072  D/MyMainActivity: setValue: 22022-08-15 10:48:57.075  D/MyMainActivity: observer: 2

懵逼树下懵逼果,懵逼树下你和我,没错setValue也和postValue一样,只接收到了最后一次发送的数值2.

3、在onCreate中 点击按钮执行for循环调用postValue

class MainActivity : AppCompatActivity() {private lateinit var activityMainBinding: ActivityMainBindingprivate val liveData = MutableLiveData<Int>()override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)activityMainBinding = ActivityMainBinding.inflate(layoutInflater)setContentView(activityMainBinding.root)activityMainBinding.btn.setOnClickListener {for (i in 0..2) {liveData.postValue(i)Log.d("MyMainActivity", "postValue: $i")}}// 订阅观察者liveData.observe(this) {Log.d("MyMainActivity", "observer: $it")}}}

//输出打印:

2022-08-15 11:01:34.418 com.example.myapplication D/MyMainActivity: postValue: 02022-08-15 11:01:34.418 com.example.myapplication D/MyMainActivity: postValue: 12022-08-15 11:01:34.418 com.example.myapplication D/MyMainActivity: postValue: 22022-08-15 11:01:34.426 com.example.myapplication D/MyMainActivity: observer: 2

这个例子的结果同第一个一样,postValue连续发送数据,最后只接收到最后的数据。

4、在onCreate中 点击按钮执行for循环调用setValue


class MainActivity : AppCompatActivity() {private lateinit var activityMainBinding: ActivityMainBindingprivate val liveData = MutableLiveData<Int>()override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)activityMainBinding = ActivityMainBinding.inflate(layoutInflater)setContentView(activityMainBinding.root)activityMainBinding.btn.setOnClickListener {for (i in 0..2) {liveData.value = iLog.d("MyMainActivity", "setValue: $i")}}// 订阅观察者liveData.observe(this, object : androidx.lifecycle.Observer<Int> {override fun onChanged(it: Int?) {Log.d("MyMainActivity", "observer: $it")}})//lambda写法(后面都用这种写法)//    liveData.observe(this) {//        Log.d("MyMainActivity", "observer: $it")//    }}}

输出:

2022-08-15 11:02:29.333 D/MyMainActivity: observer: 02022-08-15 11:02:29.333 D/MyMainActivity: setValue: 02022-08-15 11:02:29.333 D/MyMainActivity: observer: 12022-08-15 11:02:29.333 D/MyMainActivity: setValue: 12022-08-15 11:02:29.333 D/MyMainActivity: observer: 22022-08-15 11:02:29.333 D/MyMainActivity: setValue: 2

守得云开见月明,终于见到想要的结果了。setValue连续发送数据,每次数据都能被接收到,而不是丢失数据,只能接收到最后一次发送的数据。

先分析下setValue的情况,再来捋postValue的。

/*** 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* 以上大致意思就是:设置value值,如果是活跃的observers,则会把值分发给它们* 这个函数必须在主线程调用,如果要在子线程调用就用postValue*/@MainThreadprotected void setValue(T value) {assertMainThread("setValue");//判断setValue方法是否在主线程调用,mVersion++;mData = value;//将value的值赋值给LiveData的成员属性 mData,给Observer的onChange回调dispatchingValue(null); 分发 value 这个传入参数的值为null}

以上代码可以得出结论,setValue必须在主线程执行,assertMainThread方法会判断setValue是否在主线程。其次value的值赋值给LiveData的成员属性 mData(mData给Observer的onChange回调),而dispatchingValue方法就是分发你value的,下面看下这个方法里面干了啥。

     @SuppressWarnings("WeakerAccess") /* synthetic access */void dispatchingValue(@Nullable ObserverWrapper initiator) {if (mDispatchingValue) {//默认是false 所以条件不成立 return 语句不会执行mDispatchInvalidated = true;return;}mDispatchingValue = true;do {mDispatchInvalidated = false;if (initiator != null) {// initiator 传入的值为null 所以会走到下面else判断条件里considerNotify(initiator);initiator = null;} else {// 遍历mObserversfor (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {                     considerNotify(iterator.next().getValue());if (mDispatchInvalidated) {break;}}}} while (mDispatchInvalidated);mDispatchingValue = false;}

首先第一个判断条件mDispatchingValue默认是false 所以条件不成立 return 语句不会执行。

而setValue 我们的 dispatchingValue(null)传入是null,所以代码会走到遍历mObservers的else分支里,遍历出的数据传入considerNotify里,那直接看下considerNotify里又干了啥。

  @SuppressWarnings("unchecked")private void considerNotify(ObserverWrapper observer) {if (!observer.mActive)  // 判断 observer 是否在活跃状态return;}/*检查最新状态b4调度。也许它改变了状态,但我们还没有得到事件。*我们还是先检查观察者。激活以保持它作为事件的入口。因此,即使*观察者移动到活动状态,如果我们没有收到该事件,我们最好不要*notify用于更可预测的通知命令。*/if (!observer.shouldBeActive()) {// 判断 observer 是否在活跃状态observer.activeStateChanged(false);return;}if (observer.mLastVersion >= mVersion) {// 校验 Observer 的版本号是否小于 LiveData 的版本号return;}observer.mLastVersion = mVersion;observer.mObserver.onChanged((T) mData);// 将mData传递给了 Observer 的 onChanged 方法}

三个if判断条件,如果都不成立,会走到下面onChaged回调里,下发数据。OK,那么可以大胆猜测,setValue数据会丢失,就是这三个if条件为true,导致数据未走到onChanged回调里。

第一个判断条件 if (!observer.mActive)和第二个判断条件 if (!observer.shouldBeActive()) 都是ObserverWrapper 的得属性或者方法调用出来的,所以看下ObserverWrapper里有什么名堂。

private abstract class ObserverWrapper {final Observer<? super T> mObserver;boolean mActive;int mLastVersion = START_VERSION;ObserverWrapper(Observer<? super T> observer) {mObserver = observer;}abstract boolean shouldBeActive();boolean isAttachedTo(LifecycleOwner owner) {return false;}void detachObserver() {}//通过这个方法修改mActive的值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);}}}

可以看到mActive的值在activeStateChanged方法里被重新赋值了,所以看下哪里调用了该方法并传入newActive参数就晓得了。先了解下 LiveData 的 observe 方法:

@MainThreadpublic void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {assertMainThread("observe");if (owner.getLifecycle().getCurrentState() == DESTROYED) {// ignorereturn;}// 创建了 LifecycleBoundObserver 对象,传入我们的 Observer 对象到构造函数LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);ObserverWrapper 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;}// 将 LifecycleBoundObserver 对象添加观察 Lifecycle 生命周期owner.getLifecycle().addObserver(wrapper);}

LifecycleBoundObserver 继承了 ObserverWrapper,并实现了 LifecycleEventObserver 接口用于观察生命周期事件

class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {@NonNullfinal LifecycleOwner mOwner;LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {super(observer);mOwner = owner;}// 在这里@Overrideboolean shouldBeActive() {// 返回当前生命周期至少是 STARTED 状态才为 true,否则 falsereturn mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);}@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();}}@Overrideboolean isAttachedTo(LifecycleOwner owner) {return mOwner == owner;}@Overridevoid detachObserver() {mOwner.getLifecycle().removeObserver(this);}}

以上代码需要注意:shouldBeActive()方法和onStateChanged方法里的 activeStateChanged();

activeStateChanged方法中可以看到调用了父类 ObserverWrapper 的 activeStateChanged 对象,但是传入的值是 shouldBeActive 方法的返回值,shouldBeActive 方法也是父类 ObserverWrapper 的方法,但是是抽象方法,shouldBeActive 在 LifecycleBoundObserver 中实现在上面。

因此  上面提到过的void considerNotify(ObserverWrapper observer)方法中2个判断条件已经找到

关键是看mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED)这个状态的判断。

  /*** Compares if this State is greater or equal to the given {@code state}.* @param state State to compare with* @return true if this State is greater or equal to the given {@code state}*翻译:比较这个状态是否大于或等于给定的{@code状态}。*/public boolean isAtLeast(@NonNull State state) {return compareTo(state) >= 0;}

传入的值为是一个枚举类型 STARTED,看下这个STARTED官网描述:

 public enum State {.../*** Started state for a LifecycleOwner. For an {@link android.app.Activity}, this state* is reached in two cases:* <ul>*     <li>after {@link android.app.Activity#onStart() onStart} call;*     <li><b>right before</b> {@link android.app.Activity#onPause() onPause} call.* </ul>翻译:android.app.Activity#onStart() onStar之后调用,android.app.Activity#onPause() onPause之前调用*/STARTED,...}

ok ,那就说明只能在activity生命周期中 onStart和onPause之间调用,observer.shouldBeActive为true,observer.mActive也为true,才能走onChangde回调。

所以开头第二个和第四个现象就能解释了。第四个是因为 LiveData 的观察生命周期的特性,

只有在页面活跃状态下才可以分发值,当可以点击按钮时候,当前Activity 的生命周期已经走过了 OnStart、onResume,

满足当前生命周期至少是 STARTED 的状态,setValue 到最终分发值一路畅通无阻,所以 for 循环中,每 set Value 一次,最终都会调用 Observer 的 onChanged 方法。

对于第二个的现象,为什么在 onCreate 方法中循环调用 setValue 最终只通知了最后一个值呢?

因为在 onCreate 方法中调用的 setValue,observer.mActive 一定为 false, 而且最终 for 循环走完,LiveData 的 mVersion 为 2,mData 为 2,这解释了最终 LiveData 的 mData 值为 2,

Observer 对象的 mLastVersion 也不会被赋值,始终为 -1,那么considerNotify(observer) 最后一个判断条件也找到了。

LiveData 调用 observe 时,observe 方法内,会将 Observer 对象包装为可感知生命周期的 LifecycleBoundObserver 对象,LifecycleOwner获取生命周期的状态,在 onStateChanged 中接受生命周期事件的改变,

方法内调用 LifecycleBoundObserver 的父类的 activeStateChanged 方法,传入的是 shouldBeActive() 方法的返回值,而 shouldBeActive() 方法判断  mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED),

也就是 调用 onStart 后;就在 onPause 调用之前 是返回 true。

 void activeStateChanged(boolean newActive) {// newActive 就是shouldBeActive()的返回值为true ,而mActive一直为false,所以条件不成立if (newActive == mActive) {return;}mActive = newActive;//将newActive=true 赋值给mActive ,changeActiveCounter(mActive ? 1 : -1);// 此时mActive为true  条件满足,调用 dispatchingValueif (mActive) {dispatchingValue(this);}}

这次dispatchingValue(this)传入不为null了,会去执行considerNotify(initiator)代码

@SuppressWarnings("WeakerAccess") /* synthetic access */void dispatchingValue(@Nullable ObserverWrapper initiator) {if (mDispatchingValue) {mDispatchInvalidated = true;return;}mDispatchingValue = true;do {mDispatchInvalidated = false;if (initiator != null) {//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;}
@SuppressWarnings("unchecked")private void considerNotify(ObserverWrapper observer) {if (!observer.mActive) {//mActive为true 条件不成立return;}// Check latest state b4 dispatch. Maybe it changed state but we didn't get the event yet.//// we still first check observer.active to keep it as the entrance for events. So even if// the observer moved to an active state, if we've not received that event, we better not// notify for a more predictable notification order.if (!observer.shouldBeActive()) {//shouldBeActive 条件不成立observer.activeStateChanged(false);return;}if (observer.mLastVersion >= mVersion) {//mLastVersion 值为 -1, 而 mVersion 值为 2,条件不成立return;}observer.mLastVersion = mVersion;observer.mObserver.onChanged((T) mData);//onChanged 传入了最新的值为2}

解释在代码注释中说明白了,废话不多说,少说废话。再来看下postValue的情况,先看下postValue的源码注释。

     /*** 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;// 同步代码块 使用 mDataLock 对象当锁synchronized (mDataLock) {// 如果 mPendingData 等于 NOT_SET 值 postTask 才为 truepostTask = mPendingData == NOT_SET;// postValue 传的值赋值给成员属性 mPendingDatamPendingData = value;}// 若 postTask 为 false 则 returnif (!postTask) {return;}// 发送一个消息到主线程 handler,ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);}

注释说的很明白:如果在主线程执行一个已发布的任务之前多次调用此方法,则只会分派最后一个值。但还是得捋捋为啥。

postValue内部维护了一个boolean类型的postTask,利用synchronized对一个objec对象 mDataLock加了锁,并且内部有一个全局变量mPendingData,这是问题的关键。每次postValue会将新的值赋给mPendingData,

然后会在一个Runnable中进行值的分发,且使用ArchTaskExecutor将该Runnable的任务发布到主线程中

• for 循环第一次调用 postValue 值 0 时,LiveData 的 mPendingData = NOT_SET, postTask = mPendingData == NOT_SET 为 true,mPendingData 赋值为 value 0,下面判断条件 !postTask 为 false,往消息队列插入一条消息 Runable 对象为 mPostValueRunnable。

• for 循环第二次调用 postValue 值 1 时,LiveData 的 mPendingData = 0,postTask = mPendingData == NOT_SET 为 false,mPendingData 赋值为 value 1,下面判断条件 !postTask 为 true,直接 return 不会再向主线程发消息咯。

• for 循环第三次调用 postValue 值 2 时,LiveData 的 mPendingData = 1,postTask = mPendingData == NOT_SET 为 false,mPendingData 赋值为 value 2,下面判断条件 !postTask 为 true,直接 return 也不会再向主线程发消息。

// 主线程消息队列执行到 Message 时调用的 runnable

private final Runnable mPostValueRunnable = new Runnable() {@SuppressWarnings("unchecked")@Overridepublic void run() {Object newValue;//newValue =2// 同步锁synchronized (mDataLock) {// 将 mPendingData 赋值给 newValue 对象newValue = mPendingData;//mPendingData =2// 将 mPendingData 对象值重置为 NOT_SETmPendingData = NOT_SET;}// 这里又调用了 setValue,之后就跟 LiveData.setValue 流程一样了。setValue((T) newValue);//newValue =2}};

为什么第一次postValue的值没有更新?

postValue方法内部其实是将值得回调逻辑放到了Runnable中,再post给Handler,利用Handler在主线程中更新,因此从postValue到执行Runnable,中间是存在时间差的,同时也说明 postValue是可以在子线程中发送数据的,在执行Runnable之前,因为是连续调用的postValue,

第一次mPendingData的值被第二次调用时的值覆盖掉了,最后执行Runnable时,mPendingData的值只能是最新的那个,也就是带着第二次的值触发onChange回调给UI。-

参考:https://mp.weixin.qq.com/s/cntZnRvYFglJhOuaQ0QCIw

参考:https://mp.weixin.qq.com/s/Ul4m2bCHELBk8YoUP2vewQ

LiveData的postValue丢值?setValue也丢值?相关推荐

  1. easyui的combobox下拉框初始化默认值以及保持该值一直显示的方法

    easyui的combobox下拉框默认初始值是空,下面是实现从远程加载数据之后初始化默认值,以及让该值一直排在下拉框的最顶部的方式. 目前的需求是需要在初始化的时候添加"全部数据库&quo ...

  2. C++/C++11中左值、左值引用、右值、右值引用的使用

    C++的表达式要不然是右值(rvalue),要不然就是左值(lvalue).这两个名词是从C语言继承过来的,原本是为了帮助记忆:左值可以位于赋值语句的左侧,右值则不能. 在C++语言中,二者的区别就没 ...

  3. sql-case when 条件1 then 取值1 when 条件2 then 取值2 else 取值3 end

    遇到 XXX情况 就 XXX 遇不到就 XXX 结束 case when -- then -- else -- end 例如一个3条件取值的字段: case when 条件1 then 取值1 whe ...

  4. Pandas映射(转化)dataframe中的布尔值True和False值到1和0数值、使用astype函数

    Pandas映射(转化)dataframe中的布尔值True和False值到1和0数值.使用astype函数 目录

  5. R语言dplyr包的mutate函数将列添加到dataframe中或者修改现有的数据列:使用na_if()函数将0值替换为NA值、负收入替换为NA值

    R语言dplyr包的mutate函数将列添加到dataframe中或者修改现有的数据列:使用na_if()函数将0值替换为NA值.负收入替换为NA值 目录

  6. python字典的键可以用列表吗_python字典多键值及重复键值的使用方法(详解)

    在Python中使用字典,格式如下: dict={ key1:value1 , key2;value2 ...} 在实际访问字典值时的使用格式如下: dict[key] 多键值 字典的多键值形式如下: ...

  7. jquery radio取值,checkbox取值,select取值,radio选中,checkbox选中,select选中

    例:将多个选中的checkbox的值组装成一个字符串 <script type=text/javascript> function addMem(){ //var followers = ...

  8. 记:返回方法参数的值(或多个值),

    直接贴示例代码: static void Main(string[] args) {int cs;int s= outfanhui(90, out cs); Console.WriteLine(&qu ...

  9. 值“MT_StaticRelease”不匹配值“MD_DynamicRelease”

    visual studio 编译错误: error LNK2038: 检测到"RuntimeLibrary"的不匹配项: 值"MT_StaticRelease" ...

最新文章

  1. Django博客系统(写博客页面展示)
  2. Android开发中的小技巧
  3. 关于PChar(@string)的疑惑
  4. Android 7.0 Gallery图库源码分析2 - 分析启动流程
  5. python新式类和经典类的区别?
  6. spring-boot 定时任务
  7. VueJS组件之全局组件与局部组件
  8. 并发编程总结一,进程
  9. Gitorious基本配置流程
  10. 树莓派添加USB外接硬盘
  11. 腾讯 “绝悟”论文披露技术细节。
  12. django基础 第一章 环境搭建
  13. 动静态nat综合实验
  14. 内存管理之内存映射——概述
  15. 基于mysql+php065企业公文流转系统
  16. [数学建模]马尔萨斯的人口模型及感性认识
  17. java 众数算法_众数的算法分析
  18. Thinkpad X61驱动下载及安装方法 for windows XP
  19. IDEA 一直卡在Buil(编译 write classes)报错资源不足
  20. 开发实况4.1.linux相关-CRT连接虚拟机提示用户名或密码错误

热门文章

  1. Thinkpad 电池设置 (Ubuntu)
  2. matlab利用经纬度计算距离_【Matlab】根据经纬度计算两点间的球面距离
  3. python (建立文件)制作英文字典
  4. C#MVC中的Filter过滤器使用
  5. onlyoffice sdkjs 编译
  6. 移动app之ionic框架css布局
  7. 【算法笔记第9.8节-哈夫曼编码】问题 C: 哈夫曼树(最小带权路径长度)
  8. 用php输出html代码怎么写,在PHP中输出HTML代码
  9. Selenium——浏览器设置
  10. 简单二叉树Java代码实现