2024年Android最新「知识点」LiveData为啥连续postValue两次,第一次的值会丢失?,安卓面试宝典

总结

最后对于程序员来说,要学习的知识内容、技术有太多太多,要想不被环境淘汰就只有不断提升自己,从来都是我们去适应环境,而不是环境来适应我们!

这里附上上述的技术体系图相关的几十套腾讯、头条、阿里、美团等公司20年的面试题,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分。

相信它会给大家带来很多收获:

当程序员容易,当一个优秀的程序员是需要不断学习的,从初级程序员到高级程序员,从初级架构师到资深架构师,或者走向管理,从技术经理到技术总监,每个阶段都需要掌握不同的能力。早早确定自己的职业方向,才能在工作和能力提升中甩开同龄人。

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

需要这份系统化学习资料的朋友,可以戳这里获取

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

可以看到控制台的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:

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

} 



诶~~ 值得注意的是,官方已经在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

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

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

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

image.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

这个时候全局变量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

从输出上可以看到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

Handler 相关知识,面试必问!


常问的点:

Handler Looper Message 关系是什么?

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

如何在子线程中创建 Handler?

Handler post 方法原理?

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

Android Handler 消息机制

image

Activity 相关


启动模式以及使用场景?

onNewIntent()和onConfigurationChanged()

onSaveInstanceState()和onRestoreInstanceState()

Activity 到底是如何启动的

启动模式以及使用场景

onSaveInstanceState以及onRestoreInstanceState使用

onConfigurationChanged使用以及问题解决

Activity 启动流程解析

image

Fragment


Fragment 生命周期和 Activity 对比

Fragment 之间如何进行通信

Fragment的startActivityForResult

Fragment重叠问题

Fragment 初探

Fragment 重叠, 如何通信

Fragment生命周期

image

Service 相关


进程保活

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

Service启动方式以及如何停止

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

startService 和 bingService区别

进程保活一般套路

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

image

Android布局优化之ViewStub、include、merge


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

他们的原理是什么?

ViewStub、include、merge概念解析

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

image

BroadcastReceiver 相关


注册方式,优先级

广播类型,区别

广播的使用场景,原理

Android广播动态静态注册

常见使用以及流程解析

广播源码解析

image

AsyncTask相关


AsyncTask是串行还是并行执行?

AsyncTask随着安卓版本的变迁

AsyncTask完全解析

串行还是并行

image

Android 事件分发机制


onTouch和onTouchEvent区别,调用顺序

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

滑动冲突,如何解决

事件分发机制

事件分发解析

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

image

Android View 绘制流程


简述 View 绘制流程

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

如何进行自定义 View

view 重绘机制

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

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

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

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

    image

Android Window、Activity、DecorView以及ViewRoot


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

image

Android 的核心 Binder 多进程 AIDL


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

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

多进程带来的问题

  • AIDL 使用浅析

  • binder 原理解析

  • binder 最底层解析

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

  • 多进程通信方式对比

    image

Android 高级必备 :AMS,WMS,PMS


AMS,WMS,PMS 创建过程

  • AMS,WMS,PMS全解析

  • AMS启动流程

  • WindowManagerService启动过程解析

  • PMS 启动流程解析

    image

Android ANR


为什么会发生 ANR?

如何定位 ANR?

如何避免 ANR?

什么是 ANR

如何避免以及分析方法

Android 性能优化之 ANR 详解

image

Android 内存相关


注意:内存泄漏和内存溢出是 2 个概念

什么情况下会内存泄漏?

如何防止内存泄漏?

结尾

最后小编想说:不论以后选择什么方向发展,目前重要的是把Android方面的技术学好,毕竟其实对于程序员来说,要学习的知识内容、技术有太多太多,要想不被环境淘汰就只有不断提升自己,从来都是我们去适应环境,而不是环境来适应我们!

当程序员容易,当一个优秀的程序员是需要不断学习的,从初级程序员到高级程序员,从初级架构师到资深架构师,或者走向管理,从技术经理到技术总监,每个阶段都需要掌握不同的能力。早早确定自己的职业方向,才能在工作和能力提升中甩开同龄人。

想要拿高薪实现技术提升薪水得到质的飞跃。最快捷的方式,就是有人可以带着你一起分析,这样学习起来最为高效,所以为了大家能够顺利进阶中高级、架构师,我特地为大家准备了一套高手学习的源码和框架视频等精品Android架构师教程,保证你学了以后保证薪资上升一个台阶。

当你有了学习线路,学习哪些内容,也知道以后的路怎么走了,理论看多了总要实践的。

高级UI,自定义View

UI这块知识是现今使用者最多的。当年火爆一时的Android入门培训,学会这小块知识就能随便找到不错的工作了。

不过很显然现在远远不够了,拒绝无休止的CV,亲自去项目实战,读源码,研究原理吧!

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

需要这份系统化学习资料的朋友,可以戳这里获取

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

握不同的能力。早早确定自己的职业方向,才能在工作和能力提升中甩开同龄人。

想要拿高薪实现技术提升薪水得到质的飞跃。最快捷的方式,就是有人可以带着你一起分析,这样学习起来最为高效,所以为了大家能够顺利进阶中高级、架构师,我特地为大家准备了一套高手学习的源码和框架视频等精品Android架构师教程,保证你学了以后保证薪资上升一个台阶。

当你有了学习线路,学习哪些内容,也知道以后的路怎么走了,理论看多了总要实践的。

[外链图片转存中…(img-gWa05OqV-1715669522185)]

高级UI,自定义View

UI这块知识是现今使用者最多的。当年火爆一时的Android入门培训,学会这小块知识就能随便找到不错的工作了。

不过很显然现在远远不够了,拒绝无休止的CV,亲自去项目实战,读源码,研究原理吧!

[外链图片转存中…(img-AepbD08j-1715669522186)]

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

需要这份系统化学习资料的朋友,可以戳这里获取

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

  • 7
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值