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

相关推荐
x02414 天前
Android Room(SQLite) too many SQL variables异常
sqlite·安卓·android jetpack·1024程序员节
alexhilton17 天前
深入理解观察者模式
android·kotlin·android jetpack
Wgllss17 天前
花式高阶:插件化之Dex文件的高阶用法,极少人知道的秘密
android·性能优化·android jetpack
上官阳阳20 天前
使用Compose创造有趣的动画:使用Compose共享元素
android·android jetpack
沐言人生24 天前
Android10 Framework—Init进程-15.属性变化控制Service
android·android studio·android jetpack
IAM四十二1 个月前
Android Jetpack Core
android·android studio·android jetpack
王能1 个月前
Kotlin真·全平台——Kotlin Compose Multiplatform Mobile(kotlin跨平台方案、KMP、KMM)
android·ios·kotlin·web·android jetpack·kmp·kmm
alexhilton1 个月前
让Activity更加优雅地跳转
android·kotlin·android jetpack
沐言人生1 个月前
Android10 Framework—Init进程-11.客户端操作属性
android·android studio·android jetpack
沐言人生1 个月前
Android10 Framework—Init进程-9.服务端属性值初始化
android·android studio·android jetpack