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 {
@Override
public 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的对象:SafeIterableMap
Field mObserverField = liveDataClass.getDeclaredField("mObservers");
// 设置成可修改
mObserverField.setAccessible(true);
// 获取到这个成员变量的对象
Object mObserverObject = mObserverField.get(this);
// 得到map对象的class对象:SafeIterableMap.class
Class<? 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中的value
Object 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. 获取mVersion
Field mVersion = liveDataClass.getDeclaredField("mVersion");
mVersion.setAccessible(true);
// 3. 使mLastVersion = mVersion
Object 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 {
@Override
public 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的对象:SafeIterableMap
Field mObserverField = liveDataClass.getDeclaredField("mObservers");
// 设置成可修改
mObserverField.setAccessible(true);
// 获取到这个成员变量的对象
Object mObserverObject = mObserverField.get(this);
// 得到map对象的class对象:SafeIterableMap.class
Class<? 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中的value
Object 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. 获取mVersion
Field mVersion = liveDataClass.getDeclaredField("mVersion");
mVersion.setAccessible(true);
// 3. 使mLastVersion = mVersion
Object mVersionValue = mVersion.get(this);
mLastVersion.set(observerWrapper, mVersionValue);
} catch (Exception e) {
}
}
}
}
5. 写在最后
通过反射修改LiveData,这样我们就解决了粘性事件。可以忽略第一次postValue的问题