「知识点」LiveData为啥连续postValue两次,第一次的值会丢失?(2)

/**

  • 模拟请求,连续调用两次,第一次更新值为‘Java’,

  • 第二次更新值为‘Kotlin’

*/

findViewById(R.id.button).setOnClickListener {

viewModel.updateTitlePost("Java")

viewModel.updateTitlePost("Kotlin")

}




点击模拟接口请求,连续调用两次,第一次更新值为‘Java’,第二次更新值为‘Kotlin’。



运行看看,



![image.png](https://img-blog.csdnimg.cn/img_convert/3021ddd04b80430c14cf4d78a93419c3.png)



可以看到控制台的log输出,不管点几次,只有Kotlin的值更新成功了,也就是符合小王同志的场景了,那第一次更新的Java值跑哪去了?



**为什么连续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:

  • liveData.postValue(“a”);

  • liveData.setValue(“b”);

  • The value “b” would be set at first and later the main thread would override it with

  • the value “a”.

  • 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);

}




诶~~ 值得注意的是,官方已经在postValue的注释上说明了,



> If you called this method multiple times before a main thread executed a posted task, only the last value would be dispatched.  

> 如果在主线程执行一个已发布的任务之前多次调用此方法,则只会分派最后一个值。



虽然官方直接解释了,我们还是要搞清楚原理不是。



接着看源码,postValue内部维护了一个boolean类型的postTask,利用synchronized对一个objec对象 mDataLock加了锁,并且内部有一个全局变量mPendingData,这是问题的关键。每次postValue会将新的值赋给mPendingData,然后会在一个Runnable中进行值的分发,且使用ArchTaskExecutor将该Runnable的任务发布到主线程中(题外话:这就是为什么postValue一直在主线程更新的原因)。



我通过断点的方式,跟踪了一下



viewModel.updateTitlePost(“Java”)

viewModel.updateTitlePost(“Kotlin”)




这两步的请求路线。 第一次调用viewModel.updateTitlePost(“Java”),postValue内部值如下图:



![image.png](https://img-blog.csdnimg.cn/img_convert/9777bc23b7a21cd619256c76497fb677.png)



传入的value值为“Java”,mPendingData等于初始值,postStask则为true,则直接走到了ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable)方法。 **记住这个时候mPendingData的值为“Java”**,



**我继续利用断点执行下一步,却发现直接执行了viewModel.updateTitlePost(“Kotlin”)开始了第二次的请求,并没有执行到mPostValueRunnable中,**



既然执行了viewModel.updateTitlePost(“Kotlin”)请求,postValue传入的参数也就是“Kotlin”,我们再来看看第二次请求的断点值:



![image.png](https://img-blog.csdnimg.cn/img_convert/a0c314f1041adc1e7f0a9b46993810fe.png)



value值为“Kotlin”,因为第一次postValue时,全局变量mPendingData值为“Java”,所以这次postTask = mPendingData == NOT\_SET所执行后的值为false,接着将最新的值“Kotlin”赋值给了mPendingData,**记住,此时的mPendingData值为Kotlin**。最后,如果postTask为false,则直接return了,也就是说第二次的postValue压根不会再去 postToMainThread(mPostValueRunnable)。



当第二次请求postValue执行后,mPostValueRunnable才开始执行,



![image.png](https://img-blog.csdnimg.cn/img_convert/2898fa6f02a407679a20f16ac98705ea.png)



这个时候全局变量mPendingData的值已经变为“Kotlin”了,直接携带“Kotlin”这个参数在Runnable中 执行setValue,也就是最后触发了liveData的onChange回调,也就是文章一开始提出的,只会收到一次onChange。



至此,postValue为什么会丢失值的问题已经分析结束了,那我们再来**捋一捋**。



*   **postValue方法内部其实是将值得回调逻辑放到了Runnable中,再post给Handler,利用Handler在主线程中更新,因此从postValue到执行Runnable,中间是存在时间差的。**

    

*   **在执行Runnable之前,因为是连续调用的postValue,第一次mPendingData的值被第二次调用时的值覆盖掉了,最后执行Runnable时,mPendingData的值只能是最新的那个,也就是带着第二次的值触发onChange回调给UI。**

    



“懂了,懂了,付老板yyds”,小王同志听了我的一番分(吹)析(皮)点了点头。



“那还有一个问题,**既然postValue最后会执行到Runnable,那连续两次postValue,为什么没有两次Runnable的执行呢?**”



“其实这个问题在上面分析中已经给出了答案,在postValue函数内部维护了一个boolean类型的postTask,而postTask是true还是false是由mPendingData值来决定的,第一次执行postValue,mPendingData == NOT\_SET初始值,postTask则为true,接着将参数值赋值给了mPendingData,然后开始post了一个Runnable。



这个时候开始了第二次的postValue,mPendingData由于不再等于初始值NOT\_SET,则postTask为false,postTask为false,那就直接return了,就不会再执行一个Runnable了,这就是为什么没有两次Runnable的执行。



而在Runnable中,mPendingData会被重置为NOT\_SET,开始接受新一轮的执行逻辑。”



小王默默的记在了心里。



“**那既然postValue丢失旧值是因为需要post Runnable的缘故,那setValue没有这一步,是不是就不会丢失值了。**”



“哟~~ 不错嘛,学会举一反三了,没错的,setValue不会丢值,这也是postValue和setValue的不同之处。我们可以实践看看。



其他不变,将postValue改为setValue,



![image.png](https://img-blog.csdnimg.cn/img_convert/b29b782f8166c056571f964cbe131edf.png)



从输出上可以看到activity中“Java”和“Kotlin”的值都收到了。”



这也就验证了setValue和postValue不一样,并不会丢失值。



于是,小王同志解决了bug开开心心的走了,我也戴上耳机,继续我的代码之旅。



**推荐阅读:**



[Flutter实战项目开源]( )  

[「Kotlin篇」原来,协程是这么挂起的]( )  

[【Jetpack篇】LiveData取代EventBus?LiveData的通信原理和粘性事件刨析]( )



1713886180999204")  

[【Jetpack篇】LiveData取代EventBus?LiveData的通信原理和粘性事件刨析]( )



[]( )最后

------------------------------------------------------------------



分享给大家一份面试题合集。



下面的题目都是在Android交流群大家在面试时遇到的,如果大家有好的题目或者好的见解欢迎分享,楼主将长期维护此帖。  

**参考解析**:郭霖、鸿洋、玉刚、极客时间、腾讯课堂…



**内容特点**:条理清晰,含图像化表示更加易懂。



**内容概要**:包括 Handler、Activity相关、Fragment、service、布局优化、AsyncTask相关  

、Android 事件分发机制、 Binder、Android 高级必备 :AMS,WMS,PMS、Glide、 Android 组件化与插件化等面试题和技术栈!  

![image](https://img-blog.csdnimg.cn/img_convert/c47afcb94a27d079dd57145faf431581.webp)



[]( )Handler 相关知识,面试必问!

----------------------------------------------------------------------------------



常问的点:  

Handler Looper Message 关系是什么?  

Messagequeue 的数据结构是什么?为什么要用这个数据结构?  

如何在子线程中创建 Handler?  

Handler post 方法原理?  

Android消息机制的原理及源码解析  

Android Handler 消息机制



![image](https://img-blog.csdnimg.cn/img_convert/e3256ffd4125b1ccd91e6f0c8e32ba06.webp)



[]( )Activity 相关

---------------------------------------------------------------------------



启动模式以及使用场景?  

onNewIntent()和onConfigurationChanged()  

onSaveInstanceState()和onRestoreInstanceState()  

Activity 到底是如何启动的  

启动模式以及使用场景  

onSaveInstanceState以及onRestoreInstanceState使用  

onConfigurationChanged使用以及问题解决  

Activity 启动流程解析



![image](https://img-blog.csdnimg.cn/img_convert/c47ed523fe70b4595585dbde0c2d0ed2.webp)



[]( )Fragment

------------------------------------------------------------------------



Fragment 生命周期和 Activity 对比  

Fragment 之间如何进行通信  

Fragment的startActivityForResult  

Fragment重叠问题  

Fragment 初探  

Fragment 重叠, 如何通信  

Fragment生命周期



![image](https://img-blog.csdnimg.cn/img_convert/26bc720be75e71258829b29ca5f5c372.webp)



[]( )Service 相关

--------------------------------------------------------------------------



进程保活  

Service的运行线程(生命周期方法全部在主线程)  

Service启动方式以及如何停止  

ServiceConnection里面的回调方法运行在哪个线程?  

startService 和 bingService区别  

进程保活一般套路  

关于进程保活你需要知道的一切



![image](https://img-blog.csdnimg.cn/img_convert/e569c4e55cd0c4bbfa16bb322019b66a.webp)



[]( )Android布局优化之ViewStub、include、merge

--------------------------------------------------------------------------------------------------



什么情况下使用 ViewStub、include、merge?  

他们的原理是什么?  

ViewStub、include、merge概念解析  

Android布局优化之ViewStub、include、merge使用与源码分析



![image](https://img-blog.csdnimg.cn/img_convert/c70a8e6f5f408544e22e4933299909d0.webp)



[]( )BroadcastReceiver 相关

------------------------------------------------------------------------------------



注册方式,优先级  

广播类型,区别  

广播的使用场景,原理  

Android广播动态静态注册  

常见使用以及流程解析  

广播源码解析



![image](https://img-blog.csdnimg.cn/img_convert/c1e690a6d9b2bbfe2ef410500222f9aa.webp)



[]( )AsyncTask相关

---------------------------------------------------------------------------



AsyncTask是串行还是并行执行?  

AsyncTask随着安卓版本的变迁  

AsyncTask完全解析  

串行还是并行



![image](https://img-blog.csdnimg.cn/img_convert/04c78b7764e4c731a259f421ee379012.webp)



[]( )Android 事件分发机制

------------------------------------------------------------------------------



onTouch和onTouchEvent区别,调用顺序  

dispatchTouchEvent, onTouchEvent, onInterceptTouchEvent 方法顺序以及使用场景  

滑动冲突,如何解决  

事件分发机制  

事件分发解析  

dispatchTouchEvent, onTouchEvent, onInterceptTouchEvent方法的使用场景解析



![image](https://img-blog.csdnimg.cn/img_convert/cb5310dc906182a46bc40420040b94a7.webp)



[]( )Android View 绘制流程

---------------------------------------------------------------------------------



简述 View 绘制流程  

onMeasure, onlayout, ondraw方法中需要注意的点  

如何进行自定义 View  

view 重绘机制



*   Android LayoutInflater原理分析,带你一步步深入了解View(一)

    

*   Android视图状态及重绘流程分析,带你一步步深入了解View(二)

    

*   Android视图状态及重绘流程分析,带你一步步深入了解View(三)

    

*   Android自定义View的实现方法,带你一步步深入了解View(四)

    

    ![image](https://img-blog.csdnimg.cn/img_convert/50a1cd758f00c0706fd38b050dbc25f3.webp)

    



[]( )Android Window、Activity、DecorView以及ViewRoot

-----------------------------------------------------------------------------------------------------------



Window、Activity、DecorView以及ViewRoot之间的关系



![image](https://img-blog.csdnimg.cn/img_convert/c074ca8814340217aadb02bd6caf5f18.webp)



[]( )Android 的核心 Binder 多进程 AIDL

-------------------------------------------------------------------------------------------



常见的 IPC 机制以及使用场景  

为什么安卓要用 binder 进行跨进程传输  

多进程带来的问题



*   AIDL 使用浅析

    

*   binder 原理解析

    

*   binder 最底层解析

    

*   多进程通信方式以及带来的问题

    

*   多进程通信方式对比

    

    ![image](https://img-blog.csdnimg.cn/img_convert/5b5d3b8cf7914e93bf187e0d05006d38.webp)

    



[]( )Android 高级必备 :AMS,WMS,PMS

-----------------------------------------------------------------------------------------



AMS,WMS,PMS 创建过程



*   AMS,WMS,PMS全解析

    

*   AMS启动流程

    

*   WindowManagerService启动过程解析

    

*   PMS 启动流程解析

    

    ![image](https://img-blog.csdnimg.cn/img_convert/06a33a713f1a110ea8477ab97ab9148b.webp)

    



[]( )Android ANR

---------------------------------------------------------------------------




# 最后

我一直以来都有整理练习大厂面试题的习惯,有随时跳出舒服圈的准备,也许求职者已经很满意现在的工作,薪酬,觉得习惯而且安逸。

不过如果公司突然倒闭,或者部门被裁减,还能找到这样或者更好的工作吗?

我建议各位,多刷刷面试题,知道最新的技术,每三个月可以去面试一两家公司,因为你已经有不错的工作了,所以可以带着轻松的心态去面试,同时也可以增加面试的经验。

我可以将最近整理的一线互联网公司面试真题+解析分享给大家,大概花了三个月的时间整理2246页,帮助大家学习进步。

> **由于篇幅限制,文档的详解资料太全面,细节内容太多,所以只把部分知识点截图出来粗略的介绍,每个小节点里面都有更细化的内容!以下是部分内容截图:**

![](https://img-blog.csdnimg.cn/img_convert/adb37d2f4d2185645ce1cb4945832a5a.webp?x-oss-process=image/format,png)

![部分目录截图](https://img-blog.csdnimg.cn/img_convert/3a7dadab6e966ab0d7abed2a5409d18f.webp?x-oss-process=image/format,png)



**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化学习资料的朋友,可以戳这里获取](https://bbs.csdn.net/topics/618156601)**

**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

大厂面试题的习惯,有随时跳出舒服圈的准备,也许求职者已经很满意现在的工作,薪酬,觉得习惯而且安逸。

不过如果公司突然倒闭,或者部门被裁减,还能找到这样或者更好的工作吗?

我建议各位,多刷刷面试题,知道最新的技术,每三个月可以去面试一两家公司,因为你已经有不错的工作了,所以可以带着轻松的心态去面试,同时也可以增加面试的经验。

我可以将最近整理的一线互联网公司面试真题+解析分享给大家,大概花了三个月的时间整理2246页,帮助大家学习进步。

> **由于篇幅限制,文档的详解资料太全面,细节内容太多,所以只把部分知识点截图出来粗略的介绍,每个小节点里面都有更细化的内容!以下是部分内容截图:**

[外链图片转存中...(img-JUnXmFxf-1714527432827)]

[外链图片转存中...(img-pY6lRHw5-1714527432827)]



**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化学习资料的朋友,可以戳这里获取](https://bbs.csdn.net/topics/618156601)**

**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值