当前位置: 首页 > news >正文

【安卓笔记】解决livedata粘性事件

0. 前言

关于livedata,可以看我之前写的文章:【安卓笔记】lifecycle与viewModel-CSDN博客

livedata粘性事件是指:先postValue(),后observe(),会导致observe也能收到第一次post的值的问题 

1. 先看源码

我们要如何实现,解决粘性事件的问题?

我们通过源码发现:

public abstract class LiveData<T> {···@SuppressWarnings("unchecked")private void considerNotify(ObserverWrapper observer) {if (!observer.mActive) {return;}// Check latest state b4 dispatch. Maybe it changed state but we didn't get the event yet.//// we still first check observer.active to keep it as the entrance for events. So even if// the observer moved to an active state, if we've not received that event, we better not// notify for a more predictable notification order.if (!observer.shouldBeActive()) {observer.activeStateChanged(false);return;}if (observer.mLastVersion >= mVersion) {return;}observer.mLastVersion = mVersion;observer.mObserver.onChanged((T) mData);}···
}

 其中有一段

        if (observer.mLastVersion >= mVersion) {
            return;
        }

于是就有思路,使mLastVersion >= mVersion 就可以return了

2. 思路: mLastVersion >= mVersion

为了使mLastVersion >= mVersion,我们需要重写LiveData中的方法。因此用到hook。(想了解hook可以通过我的这篇文章:【安卓笔记】RxJava的Hook机制,整体拦截器-CSDN博客,虽然说得是RxJava的hook,但是大差不差)

3. 正式开工

这边贴出重写的LiveData代码:

public static class BusMutableLiveData<T> extends MutableLiveData {@Overridepublic void observe(@NonNull LifecycleOwner owner, @NonNull Observer observer) {super.observe(owner, observer);hook(observer);}private void hook(Observer<? super T> observer) {//通过反射,来修改mVersion/*** 思路是:使mLastVersion == mVersion (mLastVersion: {@link LiveData.ObserverWrapper.mLastVersion}; mVersion: {@link LiveData.mVersion})* 详见:{@link LiveData#considerNotify}* 让下面的代码return就行*      if (observer.mLastVersion >= mVersion) {*          return;*      }* 具体操作步骤:* 1. 获取 mLastVersion :livedata --> mObservers --> mObservers.get() --> ObserverWrapper --> mLastVersion* 2. 获取 mVersion :livedata --> mVersion* 3. 使 mLastVersion = mVersion*/try {// 1. 获取mLastVersion// 获取到livedata类Class<LiveData> liveDataClass = LiveData.class;// 获取类中,成员名为mObserver的对象:SafeIterableMapField mObserverField = liveDataClass.getDeclaredField("mObservers");// 设置成可修改mObserverField.setAccessible(true);// 获取到这个成员变量的对象Object mObserverObject = mObserverField.get(this);// 得到map对象的class对象:SafeIterableMap.classClass<? extends Field> mObserversClass = mObserverField.getClass();// 获取到 mObserversClass 的get方法Method get = mObserversClass.getDeclaredMethod("get", Object.class);get.setAccessible(true);// 执行get方法Object invokeEntry = get.invoke(mObserverObject, observer);// 取到invokeEntry中的valueObject observerWrapper = null;if (invokeEntry != null && invokeEntry instanceof Map.Entry) {observerWrapper = ((Map.Entry<?, ?>) invokeEntry).getValue();}// 判空if (observerWrapper == null) {throw new NullPointerException("observerWrapper is null");}// 得到observerWrapper的类对象Class<?> superclass = observerWrapper.getClass().getSuperclass();// 获取名为mLastVersion的成员对象Field mLastVersion = superclass.getDeclaredField("mLastVersion");mLastVersion.setAccessible(true);// 2. 获取mVersionField mVersion = liveDataClass.getDeclaredField("mVersion");mVersion.setAccessible(true);// 3. 使mLastVersion = mVersionObject mVersionValue = mVersion.get(this);mLastVersion.set(observerWrapper, mVersionValue);} catch (Exception e) {}}
}

4. 如何使用

具体使用方式,可以查看我的这篇文章:【安卓笔记】lifecycle与viewModel-CSDN博客

其中 3. livedata的使用,有介绍如何使用。

修改了LiveDataBus的代码,我贴在这边:

public class LiveDataBusX {private Map<String, BusMutableLiveData<Object>> bus;   // hashMap用于存放订阅者private static LiveDataBusX liveDataBus = new LiveDataBusX();public LiveDataBusX() {bus = new HashMap<>();}public static LiveDataBusX getInstance() {return liveDataBus;}/*** 注册订阅者*/public synchronized <T> BusMutableLiveData<T> with(String key, Class<T> type) {if (!bus.containsKey(key)) {bus.put(key, new BusMutableLiveData<Object>());}return (BusMutableLiveData<T>) bus.get(key);}public static class BusMutableLiveData<T> extends MutableLiveData {@Overridepublic void observe(@NonNull LifecycleOwner owner, @NonNull Observer observer) {super.observe(owner, observer);hook(observer);}private void hook(Observer<? super T> observer) {//通过反射,来修改mVersion/*** 思路是:使mLastVersion == mVersion (mLastVersion: {@link LiveData.ObserverWrapper.mLastVersion}; mVersion: {@link LiveData.mVersion})* 详见:{@link LiveData#considerNotify}* 让下面的代码return就行*      if (observer.mLastVersion >= mVersion) {*          return;*      }* 具体操作步骤:* 1. 获取 mLastVersion :livedata --> mObservers --> mObservers.get() --> ObserverWrapper --> mLastVersion* 2. 获取 mVersion :livedata --> mVersion* 3. 使 mLastVersion = mVersion*/try {// 1. 获取mLastVersion// 获取到livedata类Class<LiveData> liveDataClass = LiveData.class;// 获取类中,成员名为mObserver的对象:SafeIterableMapField mObserverField = liveDataClass.getDeclaredField("mObservers");// 设置成可修改mObserverField.setAccessible(true);// 获取到这个成员变量的对象Object mObserverObject = mObserverField.get(this);// 得到map对象的class对象:SafeIterableMap.classClass<? extends Field> mObserversClass = mObserverField.getClass();// 获取到 mObserversClass 的get方法Method get = mObserversClass.getDeclaredMethod("get", Object.class);get.setAccessible(true);// 执行get方法Object invokeEntry = get.invoke(mObserverObject, observer);// 取到invokeEntry中的valueObject observerWrapper = null;if (invokeEntry != null && invokeEntry instanceof Map.Entry) {observerWrapper = ((Map.Entry<?, ?>) invokeEntry).getValue();}// 判空if (observerWrapper == null) {throw new NullPointerException("observerWrapper is null");}// 得到observerWrapper的类对象Class<?> superclass = observerWrapper.getClass().getSuperclass();// 获取名为mLastVersion的成员对象Field mLastVersion = superclass.getDeclaredField("mLastVersion");mLastVersion.setAccessible(true);// 2. 获取mVersionField mVersion = liveDataClass.getDeclaredField("mVersion");mVersion.setAccessible(true);// 3. 使mLastVersion = mVersionObject mVersionValue = mVersion.get(this);mLastVersion.set(observerWrapper, mVersionValue);} catch (Exception e) {}}}
}

5. 写在最后

通过反射修改LiveData,这样我们就解决了粘性事件。可以忽略第一次postValue的问题

http://www.dtcms.com/a/296977.html

相关文章:

  • 《Java语言程序设计》第2章复习题(2)
  • RePlugin 坑位使用原理与指南
  • 多源信息融合智能投资【“图神经网络+强化学习“的融合架构】【低配显卡正常运行】
  • 模拟退火算法 (Simulated Annealing, SA)简介
  • JavaWeb学习打卡14(JSP内置对象及作用域)
  • ARM汇编常见伪指令及其用法示例
  • IntelliJ IDEA中管理多版本Git子模块的完整指南
  • 智慧工厂网络升级:新型 SD-WAN 技术架构与应用解析
  • 商场导航软件:3D+AI 基于Deepseek 模型的意图识别技术解析
  • BacNet 是什么?跟 LoRaWAN 的关系是什么?
  • 将JS字节流转化为对象
  • 西安交通大学XJTU 通信/信息工程大三和部分大四 实验和课程答案
  • C++哪些运算符不能被重载?
  • kubernetes集群中部署CoreDNS服务
  • day46day47 通道注意力
  • 一种基于单片机控制的太阳能电池板系统设计
  • 集训Demo6
  • 挖掘录屏宝藏:Screenity 深度解析与使用指南
  • 《计算机网络》实验报告八 加密、数字签名与证书
  • pytest测试框架
  • AUTOSAR进阶图解==>AUTOSAR_SWS_BSWGeneral
  • 【Vue学习笔记】状态管理:Pinia 与 Vuex 的使用方法与对比【附有完整案例】
  • 网络安全入门第一课:信息收集实战手册(2)
  • C语言-指针[变量指针与指针变量]
  • Java 集合框架之----ArrayList
  • Effective Modern C++ 条款16:保证const成员函数的线程安全性
  • 网址收集总结
  • 【硬件-笔试面试题】硬件/电子工程师,笔试面试题-17,(知识点:PCB布线,传输线阻抗影响因素)
  • 第一二章笔记
  • [ComfyUI] --ComfyUI 是什么?比 Stable Diffusion WebUI 强在哪?