Android JetPack~LiveData(二) 数据倒灌问题

  1. Android数据绑定技术一,企业级开发
  2. Android数据绑定技术二,企业级开发
  3. Android  JetPack~ DataBinding(数据绑定)(一)    集成与使用
  4. Android  JetPack~ LiveData (一)   介绍与使用
  5. Android JetPack~LiveData(二) 数据倒灌问题
  6. Android  JetPack~ ViewModel (一)   介绍与使用

1、数据倒灌的出现

场景:

如果我们在一个home页面获取网络数据,然后通过LiveData的观察者特性,在回调中跳转B页面,当旋转屏幕时,页面重建,LiveData又发来最后一次数据,那么直接触发了跳转B页面的代码。这就是数据倒灌引起的问题。因为LiveData的数据会保存在内存中。

数据倒灌原因:

个人描述:我们都知道LiveData是一个观察者模式,被观察者只要改变了观察者会收到通知。在页面重建时,LiveData自动推送最后一次数据供我们使用。
官方描述:ViewModel 将数据保留在内存中,这意味着开销要低于从磁盘或网络检索数据。ViewModel 与一个 Activity(或其他某个生命周期所有者)相关联,在配置更改期间保留在内存中,系统会自动将 ViewModel 与发生配置更改后产生的新 Activity 实例相关联。
 
在分发事件的时会先判断mVersion 和mLastVersion,当mLastVersion < mVersion时会onChanged((T) mData);进行分发。每次设置setValue时mVersion++,然后赋值给mLastVersion。
private abstract class ObserverWrapper {
    final Observer<? super T> mObserver;
    boolean mActive;
    // 第一处
    int mLastVersion = START_VERSION;
}
    private void considerNotify(ObserverWrapper observer) {
        ...
        // 第二处
        if (observer.mLastVersion >= mVersion) {
            return;
        }
        // 第三处
        observer.mLastVersion = mVersion;
        observer.mObserver.onChanged((T) mData);
    }
从上面实验结果可知,屏幕旋转前,observer.mLastVersion == mVersion ==2。但是屏幕旋转后,mLastVersion的值却变成了-1。这里就是问题所在了。
 
 

倒灌原因小结

Activity异常销毁然后重建,ViewModel会保存销毁之前的数据,然后在Activity重建完成后进行数据恢复,所以LiveData成员变量中的mVersion会恢复到重建之前的值。
但是Activity重建后会调用LiveData的observe()方法,方法内部会重新new一个实例,会将mLastVersion恢复到初始值。
由于LiveData本身的特性,Activity的生命周期由非活跃变成活跃时,LiveData会触发事件分发,导致屏幕旋转或者切换系统语言后出现数据倒灌。
 

注意

但是这里有一点要非常注意:系统内存不足,杀到应用后台,也会导致Activity重建,但是不会LiveData导致数据倒灌。
问题找到了,那如何防止数据倒灌呢?

解决办法

再来回顾下,数据倒灌的常见方式:
  • 屏幕旋转
  • 用户手动切换系统语言
方案:
  • 如果应用不需要横屏,就设置为永久竖屏。
  • 如果当前Activity回到前台LiveData不需要接收最新的数据,可以使用下面三中扩展的LiveData

 

待续。。。。。

 

 

 

posted on 2023-05-02 21:07  TMusketeer  阅读(308)  评论(0编辑  收藏  举报