2019-04-02

LiveDataBus

項(xiàng)目開(kāi)發(fā)中所能使用到的組建通信方式亏栈?

Intent

Handler

Broadcast

Interface

AIDL

已有的組建通信框架:

Rxjava

優(yōu)點(diǎn):效率高绒北,無(wú)內(nèi)存泄漏镇饮,具有生命周期

缺點(diǎn):基于Rxjava,學(xué)習(xí)成本太大储藐,而且依賴(lài)的包有2.2M嘶是,會(huì)對(duì)我們的apk產(chǎn)生一定的負(fù)擔(dān)

EventBus

優(yōu)點(diǎn):使用簡(jiǎn)單聂喇,能達(dá)到項(xiàng)目基本需求

缺點(diǎn):混淆問(wèn)題蔚携,無(wú)法感知生命周期酝蜒,很難追蹤到發(fā)布者

LiveDataBus

使用簡(jiǎn)單

代碼量少

官方提供了很穩(wěn)定的并且會(huì)一直維護(hù)的可依賴(lài)包

能感知組件的生命周期

不會(huì)存在內(nèi)存泄漏

Android框架組件之Lifecycle:?

? ? 具有生命感知的亡脑,不但能夠監(jiān)聽(tīng)Activity霉咨、Fragment的生命周期途戒,還能夠回調(diào)相應(yīng)的方法僵驰,同時(shí)他能夠?qū)崟r(shí)的獲取當(dāng)前Activity、Fragment的狀態(tài)

LiveData

是一個(gè)數(shù)據(jù)持有類(lèi)打月,持有數(shù)據(jù)并且這個(gè)數(shù)據(jù)能被觀察者監(jiān)聽(tīng),而且它是和lifecycle綁定的,具有生命周期感知的,解決內(nèi)存泄漏和引用問(wèn)題猪瞬。

Hook

? ? 可以用在事件傳送的過(guò)程中截獲并監(jiān)聽(tīng)事件的傳輸陈瘦,將自身的代碼與系統(tǒng)方法進(jìn)行融入痊项。這樣,當(dāng)這些方法被調(diào)用時(shí)皱埠,也就可以執(zhí)行我們自己的代碼边器,這也就是面向?qū)ο蟮木幊趟枷耄ˋOP)

其實(shí)就是通過(guò)反射獲取到Hook點(diǎn),然后在Hook點(diǎn)執(zhí)行我們要插入的方法或者改變?cè)镜倪壿嫷膮?shù)恒界,然后再接著執(zhí)行它原本要執(zhí)行的邏輯仗处。

以下內(nèi)容來(lái)源于

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

發(fā)布/訂閱模式

訂閱發(fā)布模式定義了一種“一對(duì)多”的依賴(lài)關(guān)系,讓多個(gè)訂閱者對(duì)象同時(shí)監(jiān)聽(tīng)某一個(gè)主題對(duì)象吃环。這個(gè)主題對(duì)象在自身狀態(tài)變化時(shí)郁轻,會(huì)通知所有訂閱者對(duì)象,使它們能夠自動(dòng)更新自己的狀態(tài)竭沫。


從EventBus說(shuō)起

EventBus是一個(gè)Android事件發(fā)布/訂閱框架蜕提,通過(guò)解耦發(fā)布者和訂閱者簡(jiǎn)化Android事件傳遞谎势。EventBus可以代替Android傳統(tǒng)的Intent脏榆、Handler台谍、Broadcast或接口回調(diào)趁蕊,在Fragment介衔、Activity、Service線(xiàn)程之間傳遞數(shù)據(jù)赃泡,執(zhí)行方法俄烁。

EventBus最大的特點(diǎn)就是簡(jiǎn)潔级野、解耦蓖柔。在沒(méi)有EventBus之前我們通常用廣播來(lái)實(shí)現(xiàn)監(jiān)聽(tīng),或者自定義接口函數(shù)回調(diào)牢贸,有的場(chǎng)景我們也可以直接用Intent攜帶簡(jiǎn)單數(shù)據(jù)潜索,或者在線(xiàn)程之間通過(guò)Handler處理消息傳遞竹习。但無(wú)論是廣播還是Handler機(jī)制遠(yuǎn)遠(yuǎn)不能滿(mǎn)足我們高效的開(kāi)發(fā)列牺。EventBus簡(jiǎn)化了應(yīng)用程序內(nèi)各組件間昔园、組件與后臺(tái)線(xiàn)程間的通信默刚。EventBus一經(jīng)推出,便受到廣大開(kāi)發(fā)者的推崇澜搅。

現(xiàn)在看來(lái)勉躺,EventBus給Android開(kāi)發(fā)者世界帶來(lái)了一種新的框架和思想饵溅,就是消息的發(fā)布和訂閱妇萄。這種思想在其后很多框架中都得到了應(yīng)用。

幸乒、

RxBus的出現(xiàn)

RxBus不是一個(gè)庫(kù)唇牧,而是一個(gè)文件丐重,實(shí)現(xiàn)只有短短30行代碼扮惦。RxBus本身不需要過(guò)多分析,它的強(qiáng)大完全來(lái)自于它基于的RxJava技術(shù)。響應(yīng)式編程(Reactive Programming)技術(shù)這幾年特別火纳猪,RxJava是它在Java上的實(shí)作桃笙。RxJava天生就是發(fā)布/訂閱模式搏明,而且很容易處理線(xiàn)程切換星著。所以,RxBus憑借區(qū)區(qū)30行代碼虚循,就敢挑戰(zhàn)EventBus“江湖老大”的地位横缔。

RxBus原理

在RxJava中有個(gè)Subject類(lèi)茎刚,它繼承Observable類(lèi),同時(shí)實(shí)現(xiàn)了Observer接口粮坞,因此Subject可以同時(shí)擔(dān)當(dāng)訂閱者和被訂閱者的角色,我們使用Subject的子類(lèi)PublishSubject來(lái)創(chuàng)建一個(gè)Subject對(duì)象(PublishSubject只有被訂閱后才會(huì)把接收到的事件立刻發(fā)送給訂閱者)妇押,在需要接收事件的地方敲霍,訂閱該Subject對(duì)象肩杈,之后如果Subject對(duì)象接收到事件解寝,則會(huì)發(fā)射給該訂閱者聋伦,此時(shí)Subject對(duì)象充當(dāng)被訂閱者的角色。

完成了訂閱兵拢,在需要發(fā)送事件的地方將事件發(fā)送給之前被訂閱的Subject對(duì)象说铃,則此時(shí)Subject對(duì)象作為訂閱者接收事件腻扇,然后會(huì)立刻將事件轉(zhuǎn)發(fā)給訂閱該Subject對(duì)象的訂閱者砾嫉,以便訂閱者處理相應(yīng)事件焰枢,到這里就完成了事件的發(fā)送與處理。

最后就是取消訂閱的操作了暑椰,RxJava中一汽,訂閱操作會(huì)返回一個(gè)Subscription對(duì)象召夹,以便在合適的時(shí)機(jī)取消訂閱,防止內(nèi)存泄漏纱意,如果一個(gè)類(lèi)產(chǎn)生多個(gè)Subscription對(duì)象偷霉,我們可以用一個(gè)CompositeSubscription存儲(chǔ)起來(lái)类少,以進(jìn)行批量的取消訂閱渔扎。

RxBus有很多實(shí)現(xiàn),如:

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

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

其實(shí)正如前面所說(shuō)的残吩,RxBus的原理是如此簡(jiǎn)單世剖,我們自己都可以寫(xiě)出一個(gè)RxBus的實(shí)現(xiàn):

基于RxJava1的RxBus實(shí)現(xiàn):

publicfinalclassRxBus{

privatefinalSubject?bus;

privateRxBus(){

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

}

privatestaticclassSingletonHolder{

privatestaticfinalRxBus?defaultRxBus?=newRxBus();

}

publicstaticRxBusgetInstance(){

returnSingletonHolder.defaultRxBus;

}

/*

?????*?發(fā)送

?????*/

publicvoidpost(Object?o){

bus.onNext(o);

}

/*

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

?????*/

publicbooleanhasObservable(){

returnbus.hasObservers();

}

/*

?????*?轉(zhuǎn)換為特定類(lèi)型的Obserbale

?????*/

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

returnbus.ofType(type);

}

}

基于RxJava2的RxBus實(shí)現(xiàn):

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是一個(gè)可以被觀察的數(shù)據(jù)持有類(lèi),它可以感知并遵循Activity遭庶、Fragment或Service等組件的生命周期峦睡。正是由于LiveData對(duì)組件生命周期可感知特點(diǎn)榨了,因此可以做到僅在組件處于生命周期的激活狀態(tài)時(shí)才更新UI數(shù)據(jù)攘蔽。

LiveData需要一個(gè)觀察者對(duì)象满俗,一般是Observer類(lèi)的具體實(shí)現(xiàn)作岖。當(dāng)觀察者的生命周期處于STARTED或RESUMED狀態(tài)時(shí)痘儡,LiveData會(huì)通知觀察者數(shù)據(jù)變化沉删;在觀察者處于其他狀態(tài)時(shí)丑念,即使LiveData的數(shù)據(jù)變化了结蟋,也不會(huì)通知嵌屎。

LiveData的優(yōu)點(diǎn)

UI和實(shí)時(shí)數(shù)據(jù)保持一致宝惰,因?yàn)長(zhǎng)iveData采用的是觀察者模式,這樣一來(lái)就可以在數(shù)據(jù)發(fā)生改變時(shí)獲得通知尊残,更新UI寝衫。

避免內(nèi)存泄漏慰毅,觀察者被綁定到組件的生命周期上扎阶,當(dāng)被綁定的組件銷(xiāo)毀(destroy)時(shí)东臀,觀察者會(huì)立刻自動(dòng)清理自身的數(shù)據(jù)。

不會(huì)再產(chǎn)生由于Activity處于stop狀態(tài)而引起的崩潰贱勃,例如:當(dāng)Activity處于后臺(tái)狀態(tài)時(shí)贵扰,是不會(huì)收到LiveData的任何事件的戚绕。

不需要再解決生命周期帶來(lái)的問(wèn)題,LiveData可以感知被綁定的組件的生命周期耘子,只有在活躍狀態(tài)才會(huì)通知數(shù)據(jù)變化谷誓。

實(shí)時(shí)數(shù)據(jù)刷新捍歪,當(dāng)組件處于活躍狀態(tài)或者從不活躍狀態(tài)到活躍狀態(tài)時(shí)總是能收到最新的數(shù)據(jù)鸵钝。

解決Configuration Change問(wèn)題恩商,在屏幕發(fā)生旋轉(zhuǎn)或者被回收再次啟動(dòng)怠堪,立刻就能收到最新的數(shù)據(jù)。

談一談Android Architecture Components

Android Architecture Components的核心是Lifecycle锤窑、LiveData、ViewModel 以及 Room探橱,通過(guò)它可以非常優(yōu)雅的讓數(shù)據(jù)與界面進(jìn)行交互隧膏,并做一些持久化的操作胞枕,高度解耦,自動(dòng)管理生命周期决乎,而且不用擔(dān)心內(nèi)存泄漏的問(wèn)題构诚。

Room

一個(gè)強(qiáng)大的SQLite對(duì)象映射庫(kù)范嘱。

ViewModel

一類(lèi)對(duì)象,它用于為UI組件提供數(shù)據(jù)叠聋,在設(shè)備配置發(fā)生變更時(shí)依舊可以存活碌补。

LiveData一個(gè)可感知生命周期脑慧、可被觀察的數(shù)據(jù)容器砰盐,它可以存儲(chǔ)數(shù)據(jù)岩梳,還會(huì)在數(shù)據(jù)發(fā)生改變時(shí)進(jìn)行提醒。

Lifecycle

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

Android Architecture Components的特點(diǎn)

數(shù)據(jù)驅(qū)動(dòng)型編程

變化的永遠(yuǎn)是數(shù)據(jù)告材,界面無(wú)需更改斥赋。

感知生命周期产艾,防止內(nèi)存泄漏

高度解耦

數(shù)據(jù),界面高度分離隘膘。

數(shù)據(jù)持久化

數(shù)據(jù)棘幸、ViewModel不與 UI的生命周期掛鉤,不會(huì)因?yàn)榻缑娴闹亟ǘN(xiāo)毀吨悍。

重點(diǎn):為什么使用LiveData構(gòu)建數(shù)據(jù)通信總線(xiàn)LiveDataBus

LiveDataBus原理圖


LiveDataBus的實(shí)現(xiàn)

第一個(gè)實(shí)現(xiàn):

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);

}

}

短短二十行代碼育瓜,就實(shí)現(xiàn)了一個(gè)通信總線(xiàn)的全部功能躏仇,并且還具有生命周期感知功能焰手,并且使用起來(lái)也及其簡(jiǎn)單:

注冊(cè)訂閱:

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

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

@Override

publicvoidonChanged(@NullableBoolean?aBoolean)?{

}

});

發(fā)送消息:

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

我們發(fā)送了一個(gè)名為"key_test"书妻,值為true的事件躲履。

這個(gè)時(shí)候訂閱者就會(huì)收到消息聊闯,并作相應(yīng)的處理菱蔬,非常簡(jiǎn)單。

問(wèn)題出現(xiàn)

對(duì)于LiveDataBus的第一版實(shí)現(xiàn)魏身,我們發(fā)現(xiàn),在使用這個(gè)LiveDataBus的過(guò)程中李皇,訂閱者會(huì)收到訂閱之前發(fā)布的消息。對(duì)于一個(gè)消息總線(xiàn)來(lái)說(shuō)茧跋,這是不可接受的瘾杭。無(wú)論EventBus或者RxBus粥烁,訂閱方都不會(huì)收到訂閱之前發(fā)出的消息。對(duì)于一個(gè)消息總線(xiàn)芥永,LiveDataBus必須要解決這個(gè)問(wèn)題埋涧。

問(wèn)題分析

怎么解決這個(gè)問(wèn)題呢奇瘦?先分析下原因:

當(dāng)LifeCircleOwner的狀態(tài)發(fā)生變化的時(shí)候耳标,會(huì)調(diào)用LiveData.ObserverWrapper的activeStateChanged函數(shù),如果這個(gè)時(shí)候ObserverWrapper的狀態(tài)是active纲仍,就會(huì)調(diào)用LiveData的dispatchingValue郑叠。

在LiveData的dispatchingValue中乡革,又會(huì)調(diào)用LiveData的considerNotify方法沸版。

在LiveData的considerNotify方法中视粮,紅框中的邏輯是關(guān)鍵蕾殴,如果ObserverWrapper的mLastVersion小于LiveData的mVersion,就會(huì)去回調(diào)mObserver的onChanged方法茴肥。而每個(gè)新的訂閱者荡灾,其version都是-1批幌,LiveData一旦設(shè)置過(guò)其version是大于-1的(每次LiveData設(shè)置值都會(huì)使其version加1),這樣就會(huì)導(dǎo)致LiveDataBus每注冊(cè)一個(gè)新的訂閱者郁稍,這個(gè)訂閱者立刻會(huì)收到一個(gè)回調(diào)耀怜,即使這個(gè)設(shè)置的動(dòng)作發(fā)生在訂閱之前财破。

問(wèn)題原因總結(jié)

對(duì)于這個(gè)問(wèn)題左痢,總結(jié)一下發(fā)生的核心原因俊性。對(duì)于LiveData描扯,其初始的version是-1,當(dāng)我們調(diào)用了其setValue或者postValue典徊,其vesion會(huì)+1卒落;對(duì)于每一個(gè)觀察者的封裝ObserverWrapper儡毕,其初始version也為-1扑媚,也就是說(shuō),每一個(gè)新注冊(cè)的觀察者檐盟,其version為-1葵萎;當(dāng)LiveData設(shè)置這個(gè)ObserverWrapper的時(shí)候羡忘,如果LiveData的version大于ObserverWrapper的version磕昼,LiveData就會(huì)強(qiáng)制把當(dāng)前value推送給Observer票从。

如何解決這個(gè)問(wèn)題

明白了問(wèn)題產(chǎn)生的原因之后峰鄙,我們來(lái)看看怎么才能解決這個(gè)問(wèn)題。很顯然魁蒜,根據(jù)之前的分析兜看,只需要在注冊(cè)一個(gè)新的訂閱者的時(shí)候把Wrapper的version設(shè)置成跟LiveData的version一致即可狭瞎。

那么怎么實(shí)現(xiàn)呢脚作,看看LiveData的observe方法,他會(huì)在步驟1創(chuàng)建一個(gè)LifecycleBoundObserver劣针,LifecycleBoundObserver是ObserverWrapper的派生類(lèi)捺典。然后會(huì)在步驟2把這個(gè)LifecycleBoundObserver放入一個(gè)私有Map容器mObservers中襟己。無(wú)論ObserverWrapper還是LifecycleBoundObserver都是私有的或者包可見(jiàn)的,所以無(wú)法通過(guò)繼承的方式更改LifecycleBoundObserver的version员咽。

那么能不能從Map容器mObservers中取到LifecycleBoundObserver贮预,然后再更改version呢仿吞?答案是肯定的,通過(guò)查看SafeIterableMap的源碼我們發(fā)現(xiàn)有一個(gè)protected的get方法峡迷。因此绘搞,在調(diào)用observe的時(shí)候看杭,我們可以通過(guò)反射拿到LifecycleBoundObserver挟伙,再把LifecycleBoundObserver的version設(shè)置成和LiveData一致即可尖阔。

對(duì)于非生命周期感知的observeForever方法來(lái)說(shuō)介却,實(shí)現(xiàn)的思路是一致的齿坷,但是具體的實(shí)現(xiàn)略有不同。observeForever的時(shí)候崎场,生成的wrapper不是LifecycleBoundObserver谭跨,而是AlwaysActiveObserver(步驟1),而且我們也沒(méi)有機(jī)會(huì)在observeForever調(diào)用完成之后再去更改AlwaysActiveObserver的version蛮瞄,因?yàn)樵趏bserveForever方法體內(nèi)挂捅,步驟3的語(yǔ)句籍凝,回調(diào)就發(fā)生了苗缩。

那么對(duì)于observeForever酱讶,如何解決這個(gè)問(wèn)題呢泻肯?既然是在調(diào)用內(nèi)回調(diào)的灶挟,那么我們可以寫(xiě)一個(gè)ObserverWrapper稚铣,把真正的回調(diào)給包裝起來(lái)墅垮。把ObserverWrapper傳給observeForever算色,那么在回調(diào)的時(shí)候我們?nèi)z查調(diào)用棧,如果回調(diào)是observeForever方法引起的峡钓,那么就不回調(diào)真正的訂閱者能岩。

LiveDataBus最終實(shí)現(xiàn)

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);

????????}

????}

}

注冊(cè)訂閱:

LiveDataBus.get()

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

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

@Override

publicvoidonChanged(@NullableString?s)?{

}

});

發(fā)送消息:

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

源碼說(shuō)明

LiveDataBus的源碼可以直接拷貝使用,也可以前往作者的GitHub倉(cāng)庫(kù)查看下載:

https://github.com/JeremyLiao/LiveDataBus

總結(jié)

本文提供了一個(gè)新的消息總線(xiàn)框架——LiveDataBus炭庙。訂閱者可以訂閱某個(gè)消息通道的消息焕蹄,發(fā)布者可以把消息發(fā)布到消息通道上阀溶。利用LiveDataBus银锻,不僅可以實(shí)現(xiàn)消息總線(xiàn)功能,而且對(duì)于訂閱者鼎姐,他們不需要關(guān)心何時(shí)取消訂閱炕桨,極大減少了因?yàn)橥浫∠嗛喸斐傻膬?nèi)存泄漏風(fēng)險(xiǎn)肯腕。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末实撒,一起剝皮案震驚了整個(gè)濱河市知态,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌寂殉,老刑警劉巖原在,帶你破解...
    沈念sama閱讀 221,273評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件村怪,死亡現(xiàn)場(chǎng)離奇詭異浮庐,居然都是意外死亡柬焕,警方通過(guò)查閱死者的電腦和手機(jī)斑举,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,349評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門(mén)富玷,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)赎懦,“玉大人幻工,你說(shuō)我怎么就攤上這事〉被冢” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 167,709評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)奸鬓。 經(jīng)常有香客問(wèn)我串远,道長(zhǎng)澡罚,這世上最難降的妖魔是什么肾请? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,520評(píng)論 1 296
  • 正文 為了忘掉前任铛铁,我火速辦了婚禮,結(jié)果婚禮上括眠,老公的妹妹穿的比我還像新娘掷豺。我一直安慰自己,他們只是感情好题画,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,515評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布婴程。 她就那樣靜靜地躺著档叔,像睡著了一般。 火紅的嫁衣襯著肌膚如雪衙四。 梳的紋絲不亂的頭發(fā)上传蹈,一...
    開(kāi)封第一講書(shū)人閱讀 52,158評(píng)論 1 308
  • 那天惦界,我揣著相機(jī)與錄音,去河邊找鬼沾歪。 笑死灾搏,一個(gè)胖子當(dāng)著我的面吹牛立润,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播泉哈,決...
    沈念sama閱讀 40,755評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼旨巷,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼采呐!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起斧吐,我...
    開(kāi)封第一講書(shū)人閱讀 39,660評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤煤率,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后洋只,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體昼捍,經(jīng)...
    沈念sama閱讀 46,203評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡妒茬,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,287評(píng)論 3 340
  • 正文 我和宋清朗相戀三年乍钻,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片多糠。...
    茶點(diǎn)故事閱讀 40,427評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡夹孔,死狀恐怖怀挠,靈堂內(nèi)的尸體忽然破棺而出害捕,到底是詐尸還是另有隱情,我是刑警寧澤吞滞,帶...
    沈念sama閱讀 36,122評(píng)論 5 349
  • 正文 年R本政府宣布裁赠,位于F島的核電站赴精,受9級(jí)特大地震影響蕾哟,放射性物質(zhì)發(fā)生泄漏莲蜘。R本人自食惡果不足惜帘营,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,801評(píng)論 3 333
  • 文/蒙蒙 一芬迄、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧杜窄,春花似錦出皇、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,272評(píng)論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)狞贱。三九已至,卻和暖如春瞎嬉,著一層夾襖步出監(jiān)牢的瞬間氧枣,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,393評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工扎谎, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留毁靶,地道東北人逊移。 一個(gè)月前我還...
    沈念sama閱讀 48,808評(píng)論 3 376
  • 正文 我出身青樓胳泉,卻偏偏與公主長(zhǎng)得像觅够,于是被迫代替她去往敵國(guó)和親喘先。 傳聞我的和親對(duì)象是個(gè)殘疾皇子窘拯,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,440評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容