Android LiveDatabus非黏性事件
原文链接:https://blog.csdn.net/luotianyi_yi/article/details/103301763
Android LiveDataBus的使用这里不再赘述,网上有很多关于这个的文章。
网上大部分篇幅采用的hook方式经亲自验证不生效,所以,经过分析,自己使用了另一种方式
1.网上取消黏性事件的方法及实验结果
在Activity中 发射(set)数据,然后 在onResume中延迟3秒后在订阅。NonStickActivityDemo的部分代码为:
LiveDatabus的代码:
试验的结果为:
可以看见 ,即使在发射之后注册观察者,仍然是可以接收上次发送的数据 也就是黏性
2.分析网上方式仍然能收到黏性事件的原因
仍然能收到黏性事件的原因,关键在于这种方式,在修改Observer的mLastVersion之前调用了super.observe(owner, observer);方法。但是如果不调用super.observe(owner, observer);那么由于此时还没有注册观察者,执行get方法拿出当前观察者对应的对象Object objectWrapperEntry = methodGet.invoke(objectObservers, observer);会返回空。那么,我们来分析下,为什么调用了super.observe(owner, observer);就会接收到黏性数据。来跟踪下源码:
进入super.Observe(owner,observer);也就是LiveData的observe(owner,observer)方法
继续跟进 ,这个方法最后会执行owner.getLifecycle().addObserver(wrapper);这个方法,其中wrapper这个参数,它是一个LifecycleBoundObserver 的实例,来看下LifecycleBoundObserver 的源码:
可以看见,LifecycleBoundObserver 是ObserverWrapper的子类,关于ObserverWrapper这里不做分析,之前的网上分析黏性事件产生原因的文章已经做了介绍。其实就是一个观察者Observer(androidx.lifecycle.Observer)的封装。
当LifecycleBoundObserver 的onStateChanged方法被回调时,如果LiveData的mVersion>observer(其实就是wrapper ObserverWrapper的实例,这里是LifecycleBoundObserver 的实例)的mLastVersion时就会调用其内部observer对象通知观察者。
那么,这个onStateChanged方法是什么时候被调用呢?为什么hook不生效?猜想一下,难道是调用supper.observe(owner,observer);之后,有了观察者,就会立即把之前的数据发送给observer?
我们来验证一下。继续跟进owner.getLifeCycle().addObserver(wrapper);方法,看看这个方法究竟干了啥。进入到了LifeCycle类里面,发现这是一个抽象方法
那么,就去找它的子类。还记得我们在Demo里面,NonStickDemo里面调用注册观察者方法
可以看见,传入了this,因此,我们可以进入AppCompatActivity中去看下getLifeCycle()方法
什么情况,没有?那去父类里面找,继续跟进,进入FragmentActivity里面,还是没有找到,那就继续跟进,ComponentActivity
原来是ComponentActivity实现了这个方法,看下这个方法,返回了mLifecycleRegistry,这个mLifecycleRegistry是LifecycleRegistry的实现类
那么,我们要查看的addObserver(wrapper)方法应该就是在LifecycleRegistry类或者它的父类里面实现的,来看下LifecycleRegistry是啥玩意儿。进去LifecycleRegistry里面看看
看关键地方,先不管这个statefulObserver是啥,也不管dispatchEvent方法里面传入的参数是啥,先进去看看。
哦豁,这样子?原来还真是,在调用owner.getLifecycle().addObserver(wrapper);这个方法添加观察者后,就会立即将之前发送的数据发送给Observer。所以,无论你后面怎么hook,观察者已经接收了数据,更改mLastVersion也没用。
3.怎么解决?
由于发送(就是调用liveData的setValue()或者postValue())事件在注册观察者之前,而且每次setValue都会使liveData的mVersion加1,由于LiveData的mVersion初始值和ObserverWrapper的mLastVersion的初始值都是-1(START_VERSION = -1)所以只要先发送数据,当注册观察者时,livaData的mVersion一定大于ObserverWrapper的初始值且大于其自身的初始值-1。
既然是因为LiveData的mVersion>Observer的mLastVersion造成黏性事件,那么,我们要想实现非粘性事件,可以在注册观察者之前,利用反射,将之前已经调用了setValue或者postValue的LiveData的mVersion设置为-1就可以了。
新建BusMutableLiveData类继承MutableLiveData,并重写其observe方法,然后在LiveDataBus类的getChanel()方法中使用,代码如下:
private class BusMutableLiveDataextends MutableLiveData {
@Override
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer observer) {
hookVersion(this);
super.observe(owner, observer);
}
}
private void hookVersion(BusMutableLiveData data) {
Class liveDataClass = LiveData.class;
Field mVersion =null;
try {
mVersion = liveDataClass.getDeclaredField("mVersion");
mVersion.setAccessible(true);
int version = ((int) mVersion.get(data));
Log.e(TAG, "hookVersion:LiveData.mVersion = " + version);
if (version != -1) {
mVersion.set(data, -1);
}
}catch (NoSuchFieldException e) {
e.printStackTrace();
}catch (IllegalAccessException e) {
e.printStackTrace();
}
}
修改后我们再来看下效果
可以看见,没有黏性数据了,也不影响正常数据的接收。
4.LiveDataBus的完整代码
public class Databus {
private static Databusdatabus;
private static StringTAG ="DatabusUtil";
private Mapcaches;
private Databus() {
caches =new HashMap<>();
}
public static DatabusgetInstance() {
if (databus ==null) {
databus =new Databus();
}
return databus;
}
private synchronized BusMutableLiveDatagetChenal(String key) {
if (caches.get(key) ==null) {
caches.put(key, new BusMutableLiveData());
}
return caches.get(key);
}
public void publishSet(String key, T value) {
MutableLiveData chenal = getChenal(key);
chenal.setValue(value);
}
public void publishPo(String key, T value) {
synchronized (Databus.class) {
MutableLiveData chenal = getChenal(key);
chenal.postValue(value);
}
}
public void regist(String key, LifecycleOwner lifecycle, Observer observer) {
getChenal(key).observe(lifecycle, observer);
}
private class BusMutableLiveDataextends MutableLiveData {
@Override
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer observer) {
hookVersion(this);
super.observe(owner, observer);
}
}
private void hookVersion(BusMutableLiveData data) {
Class liveDataClass = LiveData.class;
Field mVersion =null;
try {
mVersion = liveDataClass.getDeclaredField("mVersion");
mVersion.setAccessible(true);
int version = ((int) mVersion.get(data));
Log.e(TAG, "hookVersion:LiveData.mVersion = " + version);
if (version != -1) {
mVersion.set(data, -1);
}
}catch (NoSuchFieldException e) {
e.printStackTrace();
}catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
5.结语
本人是初学者,在使用过程中发现了这个问题,如果有理解不恰当之处,欢迎大家提出宝贵的意见。