Android LiveDatabus非黏性事件

Android LiveDatabus非黏性事件

原文鏈接:https://blog.csdn.net/luotianyi_yi/article/details/103301763


Android LiveDataBus的使用這里不再贅述,網(wǎng)上有很多關(guān)于這個的文章。

網(wǎng)上大部分篇幅采用的hook方式經(jīng)親自驗(yàn)證不生效,所以,經(jīng)過分析,自己使用了另一種方式


1.網(wǎng)上取消黏性事件的方法及實(shí)驗(yàn)結(jié)果

在Activity中 發(fā)射(set)數(shù)據(jù),然后 在onResume中延遲3秒后在訂閱。NonStickActivityDemo的部分代碼為:

?

?

LiveDatabus的代碼:

試驗(yàn)的結(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 的實(shí)例,來看下LifecycleBoundObserver 的源碼:

可以看見,LifecycleBoundObserver 是ObserverWrapper的子類,關(guān)于ObserverWrapper這里不做分析,之前的網(wǎng)上分析黏性事件產(chǎn)生原因的文章已經(jīng)做了介紹。其實(shí)就是一個觀察者Observer(androidx.lifecycle.Observer)的封裝。

當(dāng)LifecycleBoundObserver 的onStateChanged方法被回調(diào)時,如果LiveData的mVersion>observer(其實(shí)就是wrapper ObserverWrapper的實(shí)例,這里是LifecycleBoundObserver 的實(shí)例)的mLastVersion時就會調(diào)用其內(nèi)部observer對象通知觀察者。

那么,這個onStateChanged方法是什么時候被調(diào)用呢?為什么hook不生效?猜想一下,難道是調(diào)用supper.observe(owner,observer);之后,有了觀察者,就會立即把之前的數(shù)據(jù)發(fā)送給observer?

我們來驗(yàn)證一下。繼續(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實(shí)現(xiàn)了這個方法,看下這個方法,返回了mLifecycleRegistry,這個mLifecycleRegistry是LifecycleRegistry的實(shí)現(xiàn)類

那么,我們要查看的addObserver(wrapper)方法應(yīng)該就是在LifecycleRegistry類或者它的父類里面實(shí)現(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。

既然是因?yàn)長iveData的mVersion>Observer的mLastVersion造成黏性事件,那么,我們要想實(shí)現(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)之處,歡迎大家提出寶貴的意見。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容