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里保障了数据的持久性

相关推荐
开发者阿伟9 小时前
Android Jetpack DataBinding源码解析与实践
android·android jetpack
alexhilton6 天前
Android技巧:学习使用GridLayout
android·kotlin·android jetpack
Wgllss13 天前
轻松搞定Android蓝牙打印机,双屏异显及副屏分辨率适配解决办法
android·架构·android jetpack
alexhilton20 天前
群星闪耀的大前端开发
android·kotlin·android jetpack
一航jason1 个月前
Android Jetpack Compose 现有Java老项目集成使用compose开发
android·java·android jetpack
帅次1 个月前
Android CoordinatorLayout:打造高效交互界面的利器
android·gradle·android studio·rxjava·android jetpack·androidx·appcompat
IAM四十二1 个月前
Jetpack Compose State 你用对了吗?
android·android jetpack·composer
Wgllss1 个月前
那些大厂架构师是怎样封装网络请求的?
android·架构·android jetpack
x0242 个月前
Android Room(SQLite) too many SQL variables异常
sqlite·安卓·android jetpack·1024程序员节
alexhilton2 个月前
深入理解观察者模式
android·kotlin·android jetpack