【安卓笔记】解决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的问题