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