解决LiveData数据倒灌/粘性数据

2023-10-16 06:10

本文主要是介绍解决LiveData数据倒灌/粘性数据,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

数据倒灌原因

原因有很多,比如旋转屏幕导致Activity重建,看官方解释:

ViewModel 将数据保留在内存中,这意味着开销要低于从磁盘或网络检索数据。
ViewModel 与一个 Activity(或其他某个生命周期所有者)相关联,
在配置更改期间保留在内存中,系统会自动将 ViewModel 
与发生配置更改后产生的新 Activity 实例相关联。

也就是说 Activity异常销毁然后重建,ViewModel会保存销毁之前的数据,然后在Activity重建完成后进行数据恢复,所以LiveData成员变量中的mVersion会恢复到重建之前的值。

但是Activity重建后会调用LiveData的observe()方法,方法内部会重新new一个实例,会将mLastVersion恢复到初始值。

由于LiveData本身的特性,Activity的生命周期由非活跃变成活跃时,LiveData会触发事件分发,导致屏幕旋转后出现数据倒灌。

在Activity屏幕旋转的状态下ViewModel并不会被销毁,这样ViewModel只要持有Activity的所有数据,都可以进行状态恢复,看看官网给出的viewmodule的作用域图

 

LiveData数据分发的条件

// LiveData.java    
private void considerNotify(ObserverWrapper observer) {// 如果当前的宿主Activity不是Active状态,不分发if (!observer.mActive) {return;}// 宿主Activity的如果在后台,不分发if (!observer.shouldBeActive()) {observer.activeStateChanged(false);return;}// 当前宿主Activity的mLastVersion大于等于LiveData的mVersion,不分发// 这里就是数据倒灌的原因if (observer.mLastVersion >= mVersion) {return;}observer.mLastVersion = mVersion;// 分发事件observer.mObserver.onChanged((T) mData);
}

条件之一就是数据的版本号,在Activity销毁重建的时候会重新订阅,如果版本号大于等于mVersion就会再次分发通知,导致activity会再次收到通知。

解决方案

  1. 可以反射修改mVersion,这个不太建议使用。
  2. 利用SingleLiveEvent 使 observe#LiveData时只相应一次onChanged操作
import android.util.Log
import androidx.annotation.MainThread
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Observer
import java.util.concurrent.atomic.AtomicBoolean
class SingleLiveEvent<T> : MutableLiveData<T>() {private val mPending = AtomicBoolean(false)@MainThreadoverride fun observe(owner: LifecycleOwner, observer: Observer<in T>) {if (hasActiveObservers()) {Log.w("SingleLiveEvent", "Multiple observers registered but only one will be notified of changes.")}super.observe(owner, { t ->if (mPending.compareAndSet(true, false)) {observer.onChanged(t)}})}@MainThreadoverride fun setValue(t: T?) {mPending.set(true)super.setValue(t)}@MainThreadfun call() {value = null}}

说明:

  1. SingleLiveEvent 利用 AtomicBoolean (默认为false)进行赋值,当LiveData 进行 setValue时改变 AtomicBoolean的值(set(true))

  2. 使用 AtomicBoolean.compareAndSet(true,false)方法,先进行判断(此时的AtomicBoolean的值为true)与 compareAndSet设置的except值(第一个参数)比较,因为相等所以将第二个参数设置为AtomicBoolean值设为false函数并返回 true ),这里其实就是利用了AtomicBoolean原子性,执行了一个比较和重新赋值的过程。

  3. 当再次进入该页面虽然 LiveData值并没有改变,仍然触发了 observer方法,由于 AtomicBoolean已经为 false ,但是 except值为 true,与if 进行判断所以 并不会继续触发 onChanged(T)方法,即只有在 setValue时相应一次onChanged(T)方法。

这篇关于解决LiveData数据倒灌/粘性数据的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/219580

相关文章

SQL Server配置管理器无法打开的四种解决方法

《SQLServer配置管理器无法打开的四种解决方法》本文总结了SQLServer配置管理器无法打开的四种解决方法,文中通过图文示例介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的... 目录方法一:桌面图标进入方法二:运行窗口进入检查版本号对照表php方法三:查找文件路径方法四:检查 S

MySQL 删除数据详解(最新整理)

《MySQL删除数据详解(最新整理)》:本文主要介绍MySQL删除数据的相关知识,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录一、前言二、mysql 中的三种删除方式1.DELETE语句✅ 基本语法: 示例:2.TRUNCATE语句✅ 基本语

Redis出现中文乱码的问题及解决

《Redis出现中文乱码的问题及解决》:本文主要介绍Redis出现中文乱码的问题及解决,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1. 问题的产生2China编程. 问题的解决redihttp://www.chinasem.cns数据进制问题的解决中文乱码问题解决总结

MyBatisPlus如何优化千万级数据的CRUD

《MyBatisPlus如何优化千万级数据的CRUD》最近负责的一个项目,数据库表量级破千万,每次执行CRUD都像走钢丝,稍有不慎就引起数据库报警,本文就结合这个项目的实战经验,聊聊MyBatisPl... 目录背景一、MyBATis Plus 简介二、千万级数据的挑战三、优化 CRUD 的关键策略1. 查

python实现对数据公钥加密与私钥解密

《python实现对数据公钥加密与私钥解密》这篇文章主要为大家详细介绍了如何使用python实现对数据公钥加密与私钥解密,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录公钥私钥的生成使用公钥加密使用私钥解密公钥私钥的生成这一部分,使用python生成公钥与私钥,然后保存在两个文

mysql中的数据目录用法及说明

《mysql中的数据目录用法及说明》:本文主要介绍mysql中的数据目录用法及说明,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、背景2、版本3、数据目录4、总结1、背景安装mysql之后,在安装目录下会有一个data目录,我们创建的数据库、创建的表、插入的

Python中Tensorflow无法调用GPU问题的解决方法

《Python中Tensorflow无法调用GPU问题的解决方法》文章详解如何解决TensorFlow在Windows无法识别GPU的问题,需降级至2.10版本,安装匹配CUDA11.2和cuDNN... 当用以下代码查看GPU数量时,gpuspython返回的是一个空列表,说明tensorflow没有找到

Navicat数据表的数据添加,删除及使用sql完成数据的添加过程

《Navicat数据表的数据添加,删除及使用sql完成数据的添加过程》:本文主要介绍Navicat数据表的数据添加,删除及使用sql完成数据的添加过程,具有很好的参考价值,希望对大家有所帮助,如有... 目录Navicat数据表数据添加,删除及使用sql完成数据添加选中操作的表则出现如下界面,查看左下角从左

解决未解析的依赖项:‘net.sf.json-lib:json-lib:jar:2.4‘问题

《解决未解析的依赖项:‘net.sf.json-lib:json-lib:jar:2.4‘问题》:本文主要介绍解决未解析的依赖项:‘net.sf.json-lib:json-lib:jar:2.4... 目录未解析的依赖项:‘net.sf.json-lib:json-lib:jar:2.4‘打开pom.XM

XML重复查询一条Sql语句的解决方法

《XML重复查询一条Sql语句的解决方法》文章分析了XML重复查询与日志失效问题,指出因DTO缺少@Data注解导致日志无法格式化、空指针风险及参数穿透,进而引发性能灾难,解决方案为在Controll... 目录一、核心问题:从SQL重复执行到日志失效二、根因剖析:DTO断裂引发的级联故障三、解决方案:修复