Android Jetpack之LiveData与ViewModel

你是?

Google通过jetpack推行的更好的代码架构MMVVM的相关类,即通过LiveData和ViewModel可以很方便地实现业务代码的MVVM架构,所谓高内聚低耦合

ps:最近又推MVI了,个人理解不是很深刻,此处暂不提了

LiveData

LiveData本身是一个抽象类,基本大部分逻辑在这个抽象类声明完了,实际较多使用的mutableLiveData继承这个抽象类,里面内容也比较简单,通过声明一个泛型和对应的setValue和postValue方法,具体实现也都是super到父类的逻辑

使用上很简单,直接实例化以后调用observe方法,传入对应的lifecycleOwner以及对应的回调接口observer在里面根据返回的参数实现对应逻辑即可,对于数据的修改则在对应地方通过livedata的实例调用setValue或者postValue方法

setValue和postValue

赋值的两个方法看一下,先是setValue

首先,assetMainThread方法判断是否主线程,否则抛出异常,然后version字段自增,data字段赋值,然后进行分发,dispatching的方法内常规情况就进入中间else的部分可以看到,对livedata绑定的observers遍历每一个看是否notify他们

considerNotify判断是否active,是否active的条件是lifecycleOwner的State≥START,再判断version是否变大,都成立再执行lastVersion的更新,触发onChanged回调

再看看postValue

postValue就没有主线程判断了,执行逻辑是加锁保护了mPendingData的赋值然后把赋值逻辑setValue发送到主线程。由于只保护了mPendingData的赋值是同步的,发送子线程任务和执行并没有确保结果,所以在这段逻辑发送任务后存在多次调用情况下又把mPendingData的值改了,后面postTask的地方return,导致setValue的值和发送时的值不匹配,第一次的修改执行线程切换,到这段多次调用的时间使线程切换完成后setValue会是最新的值,所以postValue只保证到最新的值会更新

根据这些两个方法可以解释一些常见面试问题:

1.数据倒灌

lifecycleOwner在非active状态下postValue/setValue没有响应notify观察者,但是界面重新进入active触发时version字段是修改过的导致观察者onChange回调了

解决方案:

1.根据业务逻辑过滤掉第一次的逻辑

2.入侵修改version字段的值,使得liveData不是粘性的效果

2.多次postValue只有最新的值响应

postValue通过切换线程实现,但在这个逻辑对pendingData的维护,如果pendingData没有在主线程给到setValue则不执行线程切换逻辑,所以多个postValue只有第一个调用了线程切换逻辑,最后切换完主线程响应已经得到的是多次post后最新的值作为结果setValue了

3.liveData线程安全吗?

线程安全的。postValue底层通过线程切换调用到setValue,setValue有主线程判断,因此对liveData的数据修改是在主线程串行执行保证线程安全

4.liveData为什么不会内存泄漏吗?

不会,因为内存泄漏源于长周期对象持有短周期对象的引用,即匿名内部类observer持有外部activity引用,而observer又被livedata持有,一旦liveData被比activity声明周期长的对象持有就会造成潜在的内存泄漏(通常就是ViewModel),而livedata通过licycleOwner在DESTROYED状态把observer移除,解除了这条引用链,所以可以保护不造成内存泄漏

ViewModel

一般ViewModel用来持有LiveData,正常使用livedata如果在配置变化情况下会导致activity重建,那么先前修改的值会丢失,因此有了ViewModel来做界面状态下liveData的数据的保持。下面通过ViewModel的实现来探究如何实现的

常规使用需要ViewModelProvider传入一个owner然后通过类名get出来

ViewModelProvider通过一个ViewModelStoreOwner拿到一个ViewModelStore,ViewModelStore维护了一个map里面通过键值对获取对应的ViewModel实例,所以ViewModel持久化的来源就是ViewModelStoreOwner,而ViewModelStoreOwner一般是activity或者fragment,我们直接找activity的逻辑

在ViewModelStoreOwner的直接子类ComponentActivity找到ViewModelStore的管理

当我们activity横竖屏切换的时候,旧activity先销毁,新activity再执行,在ActivityThread里relaunch调用的destroy方法对lastNonConfiguration做了保存,保存的是在ActivityClientRecord,保证了对应ViewModel数据的持久性

总结

LiveData是一个用来快捷实现MVVM观察者模式的组件,通过传入的lifeCycleOwner保证界面在active状态下数据修改可以响应的ui逻辑,同时也保证了对应生命周期的绑定与释放不会造成内存泄漏。

ViewModel用来解决在界面的配置变换时生命周期响应会丢失数据的情况,通过ViewModelStoreOwner保存在NonConfigurationInstance,而NonConfigurationInstance保存在ActivityClientRecord里保障了数据的持久性

相关推荐
_一条咸鱼_4 分钟前
Android大厂面试秘籍: Activity Intent 解析与处理模块(三)
android·面试·android jetpack
_一条咸鱼_5 小时前
Android 大厂面试秘籍:Activity 生命周期原理详解
android·面试·android jetpack
_一条咸鱼_17 小时前
Android大厂面试秘籍: View 相关面试题深入分析
android·面试·android jetpack
_一条咸鱼_1 天前
深入剖析 Android Hilt 的编译期处理模块(七)
android·kotlin·android jetpack
_一条咸鱼_2 天前
深入剖析 Android Hilt 框架的依赖生命周期管理模块(六)
android·kotlin·android jetpack
_一条咸鱼_2 天前
深入剖析 Android Hilt 的模块配置与初始化模块(五)
android·kotlin·android jetpack
Wgllss2 天前
Android提升开发测试效率,程序员应该多干了些什么?
android·架构·android jetpack
Wgllss2 天前
电影电视剧网红广告屏轮播介绍视频特效制作,Compose轻松实现
android·架构·android jetpack
IT技术图谱2 天前
【绝非标题党】Lifecycle的原理及使用,看这篇就够了
android·android jetpack
alexhilton3 天前
Compose Multiplatform支持热重载(Hot Reload)了
android·kotlin·android jetpack