2019-04-02

LiveDataBus

項目開發中所能使用到的組建通信方式?

Intent

Handler

Broadcast

Interface

AIDL

已有的組建通信框架:

Rxjava

優點:效率高,無內存泄漏,具有生命周期

缺點:基于Rxjava,學習成本太大,而且依賴的包有2.2M,會對我們的apk產生一定的負擔

EventBus

優點:使用簡單,能達到項目基本需求

缺點:混淆問題,無法感知生命周期,很難追蹤到發布者

LiveDataBus

使用簡單

代碼量少

官方提供了很穩定的并且會一直維護的可依賴包

能感知組件的生命周期

不會存在內存泄漏

Android框架組件之Lifecycle:?

? ? 具有生命感知的,不但能夠監聽Activity、Fragment的生命周期,還能夠回調相應的方法,同時他能夠實時的獲取當前Activity、Fragment的狀態

LiveData

是一個數據持有類,持有數據并且這個數據能被觀察者監聽,而且它是和lifecycle綁定的,具有生命周期感知的,解決內存泄漏和引用問題。

Hook

? ? 可以用在事件傳送的過程中截獲并監聽事件的傳輸,將自身的代碼與系統方法進行融入。這樣,當這些方法被調用時,也就可以執行我們自己的代碼,這也就是面向對象的編程思想(AOP)

其實就是通過反射獲取到Hook點,然后在Hook點執行我們要插入的方法或者改變原本的邏輯的參數,然后再接著執行它原本要執行的邏輯。

以下內容來源于

https://www.cnblogs.com/meituantech/p/9376449.html

發布/訂閱模式

訂閱發布模式定義了一種“一對多”的依賴關系,讓多個訂閱者對象同時監聽某一個主題對象。這個主題對象在自身狀態變化時,會通知所有訂閱者對象,使它們能夠自動更新自己的狀態。


從EventBus說起

EventBus是一個Android事件發布/訂閱框架,通過解耦發布者和訂閱者簡化Android事件傳遞。EventBus可以代替Android傳統的Intent、Handler、Broadcast或接口回調,在Fragment、Activity、Service線程之間傳遞數據,執行方法。

EventBus最大的特點就是簡潔、解耦。在沒有EventBus之前我們通常用廣播來實現監聽,或者自定義接口函數回調,有的場景我們也可以直接用Intent攜帶簡單數據,或者在線程之間通過Handler處理消息傳遞。但無論是廣播還是Handler機制遠遠不能滿足我們高效的開發。EventBus簡化了應用程序內各組件間、組件與后臺線程間的通信。EventBus一經推出,便受到廣大開發者的推崇。

現在看來,EventBus給Android開發者世界帶來了一種新的框架和思想,就是消息的發布和訂閱。這種思想在其后很多框架中都得到了應用。

RxBus的出現

RxBus不是一個庫,而是一個文件,實現只有短短30行代碼。RxBus本身不需要過多分析,它的強大完全來自于它基于的RxJava技術。響應式編程(Reactive Programming)技術這幾年特別火,RxJava是它在Java上的實作。RxJava天生就是發布/訂閱模式,而且很容易處理線程切換。所以,RxBus憑借區區30行代碼,就敢挑戰EventBus“江湖老大”的地位。

RxBus原理

在RxJava中有個Subject類,它繼承Observable類,同時實現了Observer接口,因此Subject可以同時擔當訂閱者和被訂閱者的角色,我們使用Subject的子類PublishSubject來創建一個Subject對象(PublishSubject只有被訂閱后才會把接收到的事件立刻發送給訂閱者),在需要接收事件的地方,訂閱該Subject對象,之后如果Subject對象接收到事件,則會發射給該訂閱者,此時Subject對象充當被訂閱者的角色。

完成了訂閱,在需要發送事件的地方將事件發送給之前被訂閱的Subject對象,則此時Subject對象作為訂閱者接收事件,然后會立刻將事件轉發給訂閱該Subject對象的訂閱者,以便訂閱者處理相應事件,到這里就完成了事件的發送與處理。

最后就是取消訂閱的操作了,RxJava中,訂閱操作會返回一個Subscription對象,以便在合適的時機取消訂閱,防止內存泄漏,如果一個類產生多個Subscription對象,我們可以用一個CompositeSubscription存儲起來,以進行批量的取消訂閱。

RxBus有很多實現,如:

AndroidKnife/RxBus(https://github.com/AndroidKnife/RxBus

Blankj/RxBus(https://github.com/Blankj/RxBus

其實正如前面所說的,RxBus的原理是如此簡單,我們自己都可以寫出一個RxBus的實現:

基于RxJava1的RxBus實現:

publicfinalclassRxBus{

privatefinalSubject?bus;

privateRxBus(){

bus?=newSerializedSubject<>(PublishSubject.create());

}

privatestaticclassSingletonHolder{

privatestaticfinalRxBus?defaultRxBus?=newRxBus();

}

publicstaticRxBusgetInstance(){

returnSingletonHolder.defaultRxBus;

}

/*

?????*?發送

?????*/

publicvoidpost(Object?o){

bus.onNext(o);

}

/*

?????*?是否有Observable訂閱

?????*/

publicbooleanhasObservable(){

returnbus.hasObservers();

}

/*

?????*?轉換為特定類型的Obserbale

?????*/

publicObservable<T>?toObservable(Class<T>?type){

returnbus.ofType(type);

}

}

基于RxJava2的RxBus實現:

publicfinalclassRxBus2{

????private?final?Subject<Object>?bus;

????private?RxBus2()?{

????????//?toSerialized?method?made?bus?thread?safe

????????bus?=?PublishSubject.create().toSerialized();

????}

publicstaticRxBus2getInstance(){

????????return?Holder.BUS;

????}

privatestaticclassHolder{

????????private?static?final?RxBus2?BUS?=?new?RxBus2();

????}

publicvoidpost(Objectobj){

????????bus.onNext(obj);

????}

publicObservabletoObservable(Class?tClass){

????????return?bus.ofType(tClass);

????}

publicObservabletoObservable(){

????????return?bus;

????}

publicbooleanhasObservers(){

????????return?bus.hasObservers();

????}

}

LiveData是Android Architecture Components提出的框架。LiveData是一個可以被觀察的數據持有類,它可以感知并遵循Activity、Fragment或Service等組件的生命周期。正是由于LiveData對組件生命周期可感知特點,因此可以做到僅在組件處于生命周期的激活狀態時才更新UI數據。

LiveData需要一個觀察者對象,一般是Observer類的具體實現。當觀察者的生命周期處于STARTED或RESUMED狀態時,LiveData會通知觀察者數據變化;在觀察者處于其他狀態時,即使LiveData的數據變化了,也不會通知。

LiveData的優點

UI和實時數據保持一致,因為LiveData采用的是觀察者模式,這樣一來就可以在數據發生改變時獲得通知,更新UI。

避免內存泄漏,觀察者被綁定到組件的生命周期上,當被綁定的組件銷毀(destroy)時,觀察者會立刻自動清理自身的數據。

不會再產生由于Activity處于stop狀態而引起的崩潰,例如:當Activity處于后臺狀態時,是不會收到LiveData的任何事件的。

不需要再解決生命周期帶來的問題,LiveData可以感知被綁定的組件的生命周期,只有在活躍狀態才會通知數據變化。

實時數據刷新,當組件處于活躍狀態或者從不活躍狀態到活躍狀態時總是能收到最新的數據。

解決Configuration Change問題,在屏幕發生旋轉或者被回收再次啟動,立刻就能收到最新的數據。

談一談Android Architecture Components

Android Architecture Components的核心是Lifecycle、LiveData、ViewModel 以及 Room,通過它可以非常優雅的讓數據與界面進行交互,并做一些持久化的操作,高度解耦,自動管理生命周期,而且不用擔心內存泄漏的問題。

Room

一個強大的SQLite對象映射庫。

ViewModel

一類對象,它用于為UI組件提供數據,在設備配置發生變更時依舊可以存活。

LiveData一個可感知生命周期、可被觀察的數據容器,它可以存儲數據,還會在數據發生改變時進行提醒。

Lifecycle

包含LifeCycleOwer和LifecycleObserver,分別是生命周期所有者和生命周期感知者。

Android Architecture Components的特點

數據驅動型編程

變化的永遠是數據,界面無需更改。

感知生命周期,防止內存泄漏

高度解耦

數據,界面高度分離。

數據持久化

數據、ViewModel不與 UI的生命周期掛鉤,不會因為界面的重建而銷毀。

重點:為什么使用LiveData構建數據通信總線LiveDataBus

LiveDataBus原理圖


LiveDataBus的實現

第一個實現:

publicfinalclassLiveDataBus{

privatefinalMap>?bus;

privateLiveDataBus(){

bus?=newHashMap<>();

}

privatestaticclassSingletonHolder{

privatestaticfinalLiveDataBus?DATA_BUS?=newLiveDataBus();

}

publicstaticLiveDataBusget(){

returnSingletonHolder.DATA_BUS;

}

publicMutableLiveData<T>?getChannel(String?target,?Class<T>?type){

if(!bus.containsKey(target))?{

bus.put(target,newMutableLiveData<>());

}

return(MutableLiveData)?bus.get(target);

}

publicMutableLiveDatagetChannel(String?target){

returngetChannel(target,?Object.class);

}

}

短短二十行代碼,就實現了一個通信總線的全部功能,并且還具有生命周期感知功能,并且使用起來也及其簡單:

注冊訂閱:

LiveDataBus.get().getChannel("key_test",?Boolean.class)

.observe(this,new?Observer()?{

@Override

publicvoidonChanged(@NullableBoolean?aBoolean)?{

}

});

發送消息:

LiveDataBus.get().getChannel("key_test").setValue(true);

我們發送了一個名為"key_test",值為true的事件。

這個時候訂閱者就會收到消息,并作相應的處理,非常簡單。

問題出現

對于LiveDataBus的第一版實現,我們發現,在使用這個LiveDataBus的過程中,訂閱者會收到訂閱之前發布的消息。對于一個消息總線來說,這是不可接受的。無論EventBus或者RxBus,訂閱方都不會收到訂閱之前發出的消息。對于一個消息總線,LiveDataBus必須要解決這個問題。

問題分析

怎么解決這個問題呢?先分析下原因:

當LifeCircleOwner的狀態發生變化的時候,會調用LiveData.ObserverWrapper的activeStateChanged函數,如果這個時候ObserverWrapper的狀態是active,就會調用LiveData的dispatchingValue。

在LiveData的dispatchingValue中,又會調用LiveData的considerNotify方法。

在LiveData的considerNotify方法中,紅框中的邏輯是關鍵,如果ObserverWrapper的mLastVersion小于LiveData的mVersion,就會去回調mObserver的onChanged方法。而每個新的訂閱者,其version都是-1,LiveData一旦設置過其version是大于-1的(每次LiveData設置值都會使其version加1),這樣就會導致LiveDataBus每注冊一個新的訂閱者,這個訂閱者立刻會收到一個回調,即使這個設置的動作發生在訂閱之前。

問題原因總結

對于這個問題,總結一下發生的核心原因。對于LiveData,其初始的version是-1,當我們調用了其setValue或者postValue,其vesion會+1;對于每一個觀察者的封裝ObserverWrapper,其初始version也為-1,也就是說,每一個新注冊的觀察者,其version為-1;當LiveData設置這個ObserverWrapper的時候,如果LiveData的version大于ObserverWrapper的version,LiveData就會強制把當前value推送給Observer。

如何解決這個問題

明白了問題產生的原因之后,我們來看看怎么才能解決這個問題。很顯然,根據之前的分析,只需要在注冊一個新的訂閱者的時候把Wrapper的version設置成跟LiveData的version一致即可。

那么怎么實現呢,看看LiveData的observe方法,他會在步驟1創建一個LifecycleBoundObserver,LifecycleBoundObserver是ObserverWrapper的派生類。然后會在步驟2把這個LifecycleBoundObserver放入一個私有Map容器mObservers中。無論ObserverWrapper還是LifecycleBoundObserver都是私有的或者包可見的,所以無法通過繼承的方式更改LifecycleBoundObserver的version。

那么能不能從Map容器mObservers中取到LifecycleBoundObserver,然后再更改version呢?答案是肯定的,通過查看SafeIterableMap的源碼我們發現有一個protected的get方法。因此,在調用observe的時候,我們可以通過反射拿到LifecycleBoundObserver,再把LifecycleBoundObserver的version設置成和LiveData一致即可。

對于非生命周期感知的observeForever方法來說,實現的思路是一致的,但是具體的實現略有不同。observeForever的時候,生成的wrapper不是LifecycleBoundObserver,而是AlwaysActiveObserver(步驟1),而且我們也沒有機會在observeForever調用完成之后再去更改AlwaysActiveObserver的version,因為在observeForever方法體內,步驟3的語句,回調就發生了。

那么對于observeForever,如何解決這個問題呢?既然是在調用內回調的,那么我們可以寫一個ObserverWrapper,把真正的回調給包裝起來。把ObserverWrapper傳給observeForever,那么在回調的時候我們去檢查調用棧,如果回調是observeForever方法引起的,那么就不回調真正的訂閱者。

LiveDataBus最終實現

publicfinalclassLiveDataBus{

privatefinalMap>?bus;

privateLiveDataBus(){

bus?=newHashMap<>();

}

privatestaticclassSingletonHolder{

privatestaticfinalLiveDataBus?DEFAULT_BUS?=newLiveDataBus();

}

publicstaticLiveDataBusget(){

returnSingletonHolder.DEFAULT_BUS;

}

publicMutableLiveData<T>?with(String?key,?Class<T>?type){

if(!bus.containsKey(key))?{

bus.put(key,newBusMutableLiveData<>());

}

return(MutableLiveData)?bus.get(key);

}

publicMutableLiveDatawith(String?key){

returnwith(key,?Object.class);

}

privatestaticclassObserverWrapperimplementsObserver{

privateObserver?observer;

publicObserverWrapper(Observer<T>?observer){

this.observer?=?observer;

}

@Override

publicvoidonChanged(@Nullable?T?t){

if(observer?!=null)?{

if(isCallOnObserve())?{

return;

}

observer.onChanged(t);

}

}

privatebooleanisCallOnObserve(){

StackTraceElement[]?stackTrace?=?Thread.currentThread().getStackTrace();

if(stackTrace?!=null&&?stackTrace.length?>0)?{

for(StackTraceElement?element?:?stackTrace)?{

if("android.arch.lifecycle.LiveData".equals(element.getClassName())?&&

"observeForever".equals(element.getMethodName()))?{

returntrue;

}

}

}

returnfalse;

}

}

privatestaticclassBusMutableLiveDataextendsMutableLiveData{

privateMap?observerMap?=newHashMap<>();

@Override

publicvoidobserve(@NonNull?LifecycleOwner?owner,?@NonNull?Observer<T>?observer){

super.observe(owner,?observer);

try{

hook(observer);

}catch(Exception?e)?{

e.printStackTrace();

}

}

@Override

publicvoidobserveForever(@NonNull?Observer<T>?observer){

if(!observerMap.containsKey(observer))?{

observerMap.put(observer,newObserverWrapper(observer));

}

super.observeForever(observerMap.get(observer));

}

@Override

publicvoidremoveObserver(@NonNull?Observer<T>?observer){

Observer?realObserver?=null;

if(observerMap.containsKey(observer))?{

realObserver?=?observerMap.remove(observer);

}else{

realObserver?=?observer;

}

super.removeObserver(realObserver);

}

privatevoidhook(@NonNull?Observer<T>?observer)throwsException{

//get?wrapper's?version

????????????Class<LiveData>?classLiveData?=?LiveData.class;

????????????Field?fieldObservers?=?classLiveData.getDeclaredField("mObservers");

????????????fieldObservers.setAccessible(true);

????????????Object?objectObservers?=?fieldObservers.get(this);

????????????Class<?>?classObservers?=?objectObservers.getClass();

????????????Method?methodGet?=?classObservers.getDeclaredMethod("get",?Object.class);

????????????methodGet.setAccessible(true);

????????????Object?objectWrapperEntry?=?methodGet.invoke(objectObservers,?observer);

????????????Object?objectWrapper?=?null;

????????????if?(objectWrapperEntry?instanceof?Map.Entry)?{

????????????????objectWrapper?=?((Map.Entry)?objectWrapperEntry).getValue();

????????????}

????????????if?(objectWrapper?==?null)?{

????????????????throw?new?NullPointerException("Wrapper?can?not?be?bull!");

????????????}

????????????Class<?>?classObserverWrapper?=?objectWrapper.getClass().getSuperclass();

????????????Field?fieldLastVersion?=?classObserverWrapper.getDeclaredField("mLastVersion");

????????????fieldLastVersion.setAccessible(true);

????????????//get?livedata's?version

????????????Field?fieldVersion?=?classLiveData.getDeclaredField("mVersion");

????????????fieldVersion.setAccessible(true);

????????????Object?objectVersion?=?fieldVersion.get(this);

????????????//set?wrapper's?version

????????????fieldLastVersion.set(objectWrapper,?objectVersion);

????????}

????}

}

注冊訂閱:

LiveDataBus.get()

.with("key_test",?String.class)

.observe(this,new?Observer()?{

@Override

publicvoidonChanged(@NullableString?s)?{

}

});

發送消息:

LiveDataBus.get().with("key_test").setValue(s);

源碼說明

LiveDataBus的源碼可以直接拷貝使用,也可以前往作者的GitHub倉庫查看下載:

https://github.com/JeremyLiao/LiveDataBus

總結

本文提供了一個新的消息總線框架——LiveDataBus。訂閱者可以訂閱某個消息通道的消息,發布者可以把消息發布到消息通道上。利用LiveDataBus,不僅可以實現消息總線功能,而且對于訂閱者,他們不需要關心何時取消訂閱,極大減少了因為忘記取消訂閱造成的內存泄漏風險。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容