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

【安卓笔记】解决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.xdnf.cn/news/16188.html

相关文章:

  • 在 Alpine Linux 中创建虚拟机时 Cgroup 挂在失败的现象
  • Springboot宠物用品商城的设计与实现
  • 详解力扣高频SQL50题之197. 上升的温度【简单】
  • 星慈光编程虫2号小车讲解第二篇--向左向右平移
  • Python编程进阶知识之第五课处理数据(matplotlib)
  • Unity VS Unreal Engine ,“电影像游戏的时代” 新手如何抉择引擎?(结)
  • 100条SQL语句分类精讲:从基础到进阶的实操指南
  • 医疗系统国产化实录:SQL Server国产替代,乙方保命指南
  • 机器学习的基础知识
  • 洛谷 P1996 约瑟夫问题之题解
  • kafka的shell操作
  • 多源信息融合智能投资【“图神经网络+强化学习“的融合架构】【低配显卡正常运行】
  • MapStruct类型转换接口未自动注入到spring容器中
  • 快速将前端得依赖打为tar包(yarn.lock版本)并且推送至nexus私有依赖仓库(笔记)
  • 《C++》面向对象编程--类(下)
  • LLM中的位置嵌入矩阵(Position Embedding Matrix)是什么
  • matrix-breakout-2-morpheus靶机通关教程
  • DBA常用数据库查询语句
  • Python爬虫案例:Scrapy+XPath解析当当网网页结构
  • Lua(模块与包)
  • 【docker | 部署 】Jetson Orin与AMD平台容器化部署概述
  • Java 实现 B/S 架构详解:从基础到实战,彻底掌握浏览器/服务器编程
  • 前端性能新纪元:Rust + WebAssembly 如何在浏览器中实现10倍性能提升(以视频处理为例)
  • 【RAG优化】RAG应用中图文表格混合内容的终极检索与生成策略
  • VUE的学习
  • iOS WebView 加载失败与缓存刷新问题排查实战指南
  • 医疗行业新变革:AR 培训系统助力手术培训精准高效​
  • Oracle国产化替代:一线DBA的技术决策突围战
  • 华为OpenStack架构学习9篇 连载—— 01 OpenStack架构介绍【附全文阅读】
  • 【C++】使用箱线图算法剔除数据样本中的异常值