讨论这个问题之前,我们先看看 LiveData
的用法,这实在没什么技术难度,比如,你可以这样实例化一个LiveData
并使用它:
如你所见,LiveData
实际上就像一个 容器, 本文中它存储了一个String
类型的引用,每当这个容器内 String
的数据发生变化,我们都能在回调函数中进行对应的处理,比如 Toast。
这似乎和我们日常用到的 Button
控件的 setOnClickListener()
非常相似,实际上点击事件的监听也正是 观察者模式 的一种体现,对于观察者来说,它并不关心观察对象 数据是如何过来的,而只关心数据过来后 进行怎样的处理。
这也就是说,事件发射的上游 和 接收事件的下游 互不干涉,大幅降低了互相持有的依赖关系所带来的强耦合性。
我依然坚持学习原理比学习如何应用的优先级更高,因此我们先来一一探究LiveData
本身设计中存在的那些闪光点背后的故事。
LiveData是如何避免内存泄漏的
我们都知道,RxJava
在使用过程中,避免内存泄漏是一个不可忽视的问题,因此我们一般需要借助三方库比如RxLifecycle
、AutoDispose
来解决这个问题。
而反观LiveData
,当它被我们的Activity
订阅观察,这之后Activity
如果finish()
掉,LiveData
本身会自动“清理”以避免内存泄漏。
这是一个非常好用的特性,它的实现原理非常简单,其本质就是利用了Jetpack 架构组件中的另外一个成员—— Lifecycle。
让我们来看看LiveData
被订阅时内部的代码:
源码中的逻辑非常复杂,我们只关注核心代码:
- 1.首先我们在调用
LiveData.observer()
方法时,传递的第一个参数Acitivity
实际被向上抽象成为了LifecycleOwner
,第二个参数Obserser
实际就是我们的观察后的回调。
这里我们需要注意的是,执行
LiveData.observer()
方法时 必须处于主线程,否则会因为断言失败而抛出异常。
- 2.方法内部实际上将我们传入的2个参数包装成了一个新的
LifecycleBoundObserver
对象,它实现了 Lifecycle 组件中的LifecycleObserver
接口:
这里就解释了为什么LiveData
能够 自动解除订阅而避免内存泄漏 了,因为它内部能够感应到Activity
或者Fragment
的生命周期。
这种设计非常巧妙——在我们初识 Lifecycle 组件时,总是下意识认为它能够对大的对象进行有效生命周期的管理(比如 Presenter),实际上,这种生命周期的管理我们完全可以应用到各个功能的基础组件中,比如大到吃内存的 MediaPlayer(多媒体播放器)、绘制设计复杂的 自定义View,小到随处可见的LiveData
,都可以通过实现LifecycleObserver
接口达到 感应生命周期并内部释放重的资源 的目的。
关于上述代码中注释了 更新LiveData的活跃状态 的源码,我们先跳过,稍后我们会详细探讨它。
-
- 我们继续回到上上一个源码片段的第三步中,对于一个可观察的
LiveData
来讲,当然存在多个观察者同时订阅观察的情况,因此考虑到这一点,Google的工程师们为每一个LiveData
配置了一个Map
存储所有的观察者。
- 我们继续回到上上一个源码片段的第三步中,对于一个可观察的
- 4.到了这一步,我们将第2步包装生成的对象交给我们传入的
Activity
,让它在不同的生命周期事件中去逐一通知其所有的观察者,当然也包含了我们的LiveData
。
数据更新后如何通知到回调方法?
LiveData
原生的API提供了2种方式供开发者更新数据, 分别是 setValue()
和postValue()
,官方文档明确标明:setValue()
方法必须在 主线程 进行调用,而postValue()
方法更适合在执行较重工作 子线程 中进行调用(比如网络请求等)——在所有情况下,调用setValue()
或postValue()
都会 触发观察者并更新UI。
柿子挑软的捏,我们先看setValue()
方法的实现原理:
通过保留最终的核心代码,我们很清晰了解了setValue()
方法为什么能更新LiveData
的值,并且通知到回调函数中的代码去执行,比如更新UI。
但是我们知道,普遍情况下,Android不允许在子线程更新UI,但是postValue()
方法却可以在子线程更新LiveData()
的数据,并通知更新UI,这是如何实现的呢?
其实答案已经呼之欲出了,就是通过 Handler
:
现在你已经对LiveData
整体了一个基本的了解了,接下来让我们开始去探究更细节的闪光点。
看完源码,你告诉我才算入门?
LiveData
本身非常简单,毕竟它本身的源码一共也就500行左右,也许你要说 准备面试粗读一遍源码就够了,很遗憾,即使是粗读了源码,也很难说能够完全招架更深入的提问…
让我们来看一道题目:在下述Activity完整的生命周期中,Activity
一共观察到了几次数据的变更——即 一共打印了几条Log ?(补充纠正,onStop()方法中值应该为 “onStop”)
公布答案:
意外的是,livedata.observer()
的本次观察并没有观察到 onCreate、onStop 和 onDestroy 的数据变更。
为什么会这样?
还记得上文提到过2次的 LiveData的活跃状态(Active) 相关代码吗?实际上,LiveData
内部存储的每一个LifecycleBoundObserver
本身都有shouldBeActive
的状态:
现在我们明白了,原来并不是只要在onDestroy()
之前为LiveData
进行更新操作,LiveData
的观察者就能响应到对应的事件的。
虽然我们明白了这一点,但是如果更深入的思考,你会又多一个问题,那就是:
- 既然
LiveData
已经能够实现在onDestroy()
的生命周期时自动解除订阅,为什么还要多此一举设置一个Active
的状态呢?
仔细想想,其实也不难得到答案,Activity
并非只有onDestroy()
一种状态的,更多时候,新的Activity
运行在栈顶,旧的Activity
就会运行在 background
——这时旧的Activity
会执行对应的onPause()
和onStop()
方法,我们当然不会关心运行在后台的Activity
所观察的LiveData
对象(即使数据更新了,我们也无从进行对应UI的更新操作),因此LiveData
进入 **InActive(待定、非活跃)**状态,return
并且不去执行对应的回调方法,是 非常缜密的优秀设计 。
当然,有同学提出,我如果希望这种情况下,Activity
在后台依然能够响应数据的变更,可不可以呢?当然可以,LiveData
此外还提供了observerForever()
方法,在这种情况下,它能够响应到任何生命周期中数据的变更事件:
除此之外,源码中处处都是优秀的细节,比如对于observe()
方法和observerForever()
方法对应生成的包装类,后者方法生成的是AlwaysActiveObserver
对象,统一抽象为ObserverWrapper
。
这种即使只有2种不同场景,也通过代码的设计,将公共业务进行向上抽离为抽象类的严谨,也非常值得我们学习。
小结,与更深入的思考
本来写了更多,篇幅所限,最终还是决定删除了相当一部分和 RxJava
有关的内容,这些内容并非是将 LiveData
和 RxJava
进行对比一决高下—— 例如,Google官方提供了 LiveData
和 RxJava
互相进行转换的工具类:
developer.android.com/reference/a…
值得玩味的是,官方的工具类中,LiveData
向RxJava
的转换方法,返回值并非是一个Flowable
,而是一个Publisher
接口:
正如我在注释中标注的,这个工具方法返回的是一个接口,很大程度上限制了我们对RxJava
众多强大操作符的使用,这是否是来自Google的恶意?
当然不是,对于这种行为,我的理解是Google对于LiveData
本身严格的约束——它只应该用于进行数据的观察,而不是花哨的操作;转换为Flowable当然非常简单,但是这种行为是否属于LiveData
本身职责的逾越,更准确来说,是否属于不必要的过度设计?这些是我们需要去细细揣度的。
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)
最后
今天关于面试的分享就到这里,还是那句话,有些东西你不仅要懂,而且要能够很好地表达出来,能够让面试官认可你的理解,例如Handler机制,这个是面试必问之题。有些晦涩的点,或许它只活在面试当中,实际工作当中你压根不会用到它,但是你要知道它是什么东西。
最后在这里小编分享一份自己收录整理上述技术体系图相关的几十套腾讯、头条、阿里、美团等公司2021年的面试题,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分。
还有 高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料 帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。
【Android核心高级技术PDF文档,BAT大厂面试真题解析】
【算法合集】
【延伸Android必备知识点】
【Android部分高级架构视频学习资源】
Android精讲视频领取学习后更加是如虎添翼!进军BATJ大厂等(备战)!现在都说互联网寒冬,其实无非就是你上错了车,且穿的少(技能),要是你上对车,自身技术能力够强,公司换掉的代价大,怎么可能会被裁掉,都是淘汰末端的业务Curd而已!现如今市场上初级程序员泛滥,这套教程针对Android开发工程师1-6年的人员、正处于瓶颈期,想要年后突破自己涨薪的,进阶Android中高级、架构师对你更是如鱼得水,赶快领取吧!
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
年后突破自己涨薪的,进阶Android中高级、架构师对你更是如鱼得水,赶快领取吧!
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!