Android LiveDatabus非黏性事件
原文鏈接:https://blog.csdn.net/luotianyi_yi/article/details/103301763
Android LiveDataBus的使用這里不再贅述趣席,網(wǎng)上有很多關(guān)于這個的文章耕腾。
網(wǎng)上大部分篇幅采用的hook方式經(jīng)親自驗證不生效燕差,所以梦湘,經(jīng)過分析码荔,自己使用了另一種方式
1.網(wǎng)上取消黏性事件的方法及實驗結(jié)果
在Activity中 發(fā)射(set)數(shù)據(jù)费封,然后 在onResume中延遲3秒后在訂閱涡匀。NonStickActivityDemo的部分代碼為:
?
?
LiveDatabus的代碼:
試驗的結(jié)果為:
可以看見 星压,即使在發(fā)射之后注冊觀察者践剂,仍然是可以接收上次發(fā)送的數(shù)據(jù) 也就是黏性
2.分析網(wǎng)上方式仍然能收到黏性事件的原因
仍然能收到黏性事件的原因,關(guān)鍵在于這種方式租幕,在修改Observer的mLastVersion之前調(diào)用了super.observe(owner, observer);方法舷手。但是如果不調(diào)用super.observe(owner, observer);那么由于此時還沒有注冊觀察者,執(zhí)行g(shù)et方法拿出當(dāng)前觀察者對應(yīng)的對象Object objectWrapperEntry = methodGet.invoke(objectObservers, observer);會返回空劲绪。那么男窟,我們來分析下,為什么調(diào)用了super.observe(owner, observer);就會接收到黏性數(shù)據(jù)贾富。來跟蹤下源碼:
?
進(jìn)入super.Observe(owner,observer);也就是LiveData的observe(owner歉眷,observer)方法
繼續(xù)跟進(jìn) ,這個方法最后會執(zhí)行owner.getLifecycle().addObserver(wrapper);這個方法颤枪,其中wrapper這個參數(shù)汗捡,它是一個LifecycleBoundObserver 的實例,來看下LifecycleBoundObserver 的源碼:
可以看見畏纲,LifecycleBoundObserver 是ObserverWrapper的子類扇住,關(guān)于ObserverWrapper這里不做分析,之前的網(wǎng)上分析黏性事件產(chǎn)生原因的文章已經(jīng)做了介紹盗胀。其實就是一個觀察者Observer(androidx.lifecycle.Observer)的封裝艘蹋。
當(dāng)LifecycleBoundObserver 的onStateChanged方法被回調(diào)時,如果LiveData的mVersion>observer(其實就是wrapper ObserverWrapper的實例票灰,這里是LifecycleBoundObserver 的實例)的mLastVersion時就會調(diào)用其內(nèi)部observer對象通知觀察者女阀。
那么宅荤,這個onStateChanged方法是什么時候被調(diào)用呢?為什么hook不生效浸策?猜想一下冯键,難道是調(diào)用supper.observe(owner,observer);之后,有了觀察者庸汗,就會立即把之前的數(shù)據(jù)發(fā)送給observer惫确?
我們來驗證一下。繼續(xù)跟進(jìn)owner.getLifeCycle().addObserver(wrapper);方法蚯舱,看看這個方法究竟干了啥雕薪。進(jìn)入到了LifeCycle類里面,發(fā)現(xiàn)這是一個抽象方法
那么晓淀,就去找它的子類。還記得我們在Demo里面盏档,NonStickDemo里面調(diào)用注冊觀察者方法
可以看見凶掰,傳入了this,因此,我們可以進(jìn)入AppCompatActivity中去看下getLifeCycle()方法
什么情況蜈亩,沒有懦窘?那去父類里面找,繼續(xù)跟進(jìn)稚配,進(jìn)入FragmentActivity里面畅涂,還是沒有找到,那就繼續(xù)跟進(jìn)道川,ComponentActivity
原來是ComponentActivity實現(xiàn)了這個方法午衰,看下這個方法,返回了mLifecycleRegistry,這個mLifecycleRegistry是LifecycleRegistry的實現(xiàn)類
那么冒萄,我們要查看的addObserver(wrapper)方法應(yīng)該就是在LifecycleRegistry類或者它的父類里面實現(xiàn)的臊岸,來看下LifecycleRegistry是啥玩意兒。進(jìn)去LifecycleRegistry里面看看
看關(guān)鍵地方尊流,先不管這個statefulObserver是啥帅戒,也不管dispatchEvent方法里面?zhèn)魅氲膮?shù)是啥,先進(jìn)去看看崖技。
哦豁逻住,這樣子?原來還真是迎献,在調(diào)用owner.getLifecycle().addObserver(wrapper);這個方法添加觀察者后瞎访,就會立即將之前發(fā)送的數(shù)據(jù)發(fā)送給Observer。所以忿晕,無論你后面怎么hook装诡,觀察者已經(jīng)接收了數(shù)據(jù)银受,更改mLastVersion也沒用。
3.怎么解決鸦采?
由于發(fā)送(就是調(diào)用liveData的setValue()或者postValue())事件在注冊觀察者之前宾巍,而且每次setValue都會使liveData的mVersion加1,由于LiveData的mVersion初始值和ObserverWrapper的mLastVersion的初始值都是-1(START_VERSION = -1)所以只要先發(fā)送數(shù)據(jù)渔伯,當(dāng)注冊觀察者時顶霞,livaData的mVersion一定大于ObserverWrapper的初始值且大于其自身的初始值-1。
既然是因為LiveData的mVersion>Observer的mLastVersion造成黏性事件锣吼,那么选浑,我們要想實現(xiàn)非粘性事件,可以在注冊觀察者之前玄叠,利用反射古徒,將之前已經(jīng)調(diào)用了setValue或者postValue的LiveData的mVersion設(shè)置為-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();
? ? }
}
修改后我們再來看下效果
可以看見寺惫,沒有黏性數(shù)據(jù)了疹吃,也不影響正常數(shù)據(jù)的接收。
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.結(jié)語
本人是初學(xué)者西雀,在使用過程中發(fā)現(xiàn)了這個問題萨驶,如果有理解不恰當(dāng)之處,歡迎大家提出寶貴的意見艇肴。