一個簡單好用的事件總線SimpleRxBus, 點我傳送門
在Android開發(fā)中,事件總線的庫往往是開發(fā)必備的利器之一,我經歷的幾個開發(fā)項目,都無一例外的引用了事件總線的庫,因為它能幫助我們非常簡單的實現組件之間的通信工作,極大的提高開發(fā)效率。
市面上EventBus,RxBus都是比較成熟的庫,為什么還是考慮自己開發(fā)一個呢?
主要還是用著不太順手,首先,Rxbus不支持粘性事件,這也就意味著Activity/Fragment之間的數據傳遞,還是需要寫很多Intent之類的代碼,降低了開發(fā)效率。其次,Rxbus,EventBus都需要手動注冊和注銷,稍顯麻煩。當然,最重要的因素是,通過RxJava開發(fā)一個RxBus也很方便。
因此在嘗試開發(fā)自己的RxBus之前,重點考慮下面兩點:
- 支持粘性事件
這是非常重要的,因為有了粘性事件,我們可以解決activity/Fragment之間的消息傳遞,附帶的好處是,進程內的數據傳遞,可以打破Intent的大小限制。
- 簡單易用
這個是一個很重要的原則,參考rxbus,我們依然需要處理register(),unregister()方法,這就不是很友好了。一個成熟的rxbus應該能夠學會自己注冊和注銷,作為使用者,我們只需要關心發(fā)送事件和接收事件。
如何支持粘性事件
RxJava天然的支持事件分發(fā)傳遞,比如,普通事件的傳遞,發(fā)送端我們可以直接使用PublishSubject,接收端則是普通的Observable即可,但是要支持粘性事件,我們需要考慮的東西就沒這么簡單了,首先使用什么樣的Subject能達成這樣的效果,是否有功能隱患或者性能隱患?
先來看看如何實現粘性事件的功能,我們熟知的Subject有四種:AsyncSubject,BehaviorSubject,PublishSubject,ReplaySubject,我們先一一解釋下這些東西
- AsyncSubject:只在原始Observable完成后,發(fā)射來自原始Observable的最后一個值
- BehaviorSubject:發(fā)射原始Observable最近發(fā)射的數據
- PublishSubject:會把在訂閱發(fā)生的時間點之后來自原始Observable的數據發(fā)射給觀察者
- ReplaySubject: 會發(fā)射所有來自原始Observable的數據給觀察者
從上面的介紹可以看出,AsyncSubject顯然不合適,PublishSubject看起來也不太合適,因為它不會發(fā)送訂閱之前的消息,ReplaySubject和BehaviorSubject都能發(fā)送訂閱之前的消息。
ReplaySubject最大的問題就是它會把發(fā)送的歷史消息都存起來,但是我們其實并不需要存儲所有的事件,如果事件太多會帶來不必要的內存負擔,雖然ReplaySubject能提供方法設置內部最大存儲量來控制存儲大小,但是無法細粒度的定點清除事件,因此,我們先把它作為一個性能較差備選的方案。
BehaviorSubject它只會存儲最近的一個事件,這樣不會有內存隱患,但是這個特性本身也會存在隱患。比如,在發(fā)送事件A和接收事件A之間的某個時間點,如果又發(fā)送了事件B
那么,事件A就會被拋棄。接受者就永遠無法收到事件A了。這一點,從下圖中也很容易看得出來。
這個問題不容易被發(fā)現,開發(fā)人員能夠意識到這個問題還可以避免,但是如果多人協(xié)作,項目越來越復雜的情況下,我們就很難保證不會出現這樣的問題了。因此,BehaviorSubject也不是一個好的選擇。
其實,以上四個Subject都不是最好的選擇,最終還是決定自己緩存事件,并在合適的時機清除歷。
添加事件的時機是當我們需要post(event)的時候,就把事件添加進來,那么何時清除事件呢?是消費完成之后就清除?顯然是不太合理的,參考Intent,在Activity中,可以多次獲取Intent,之后activity被銷毀了,intent才會被銷毀,因此,我們清除事件在取消訂閱的時候,也就是組件被銷毀的時候。保證了我們可以多次多地獲取同樣額數據,
自動注冊注銷
在新的事件總線庫中,只有post(event)和receive(event),至于注冊和注銷我們基本不需要處理。除了我們所關心的,沒有任何多余的工作。
框架會幫你自動注冊和注銷。注冊發(fā)生在準備接收數據的時候,即調用receive(Message)時,而注銷的時機就顯然是當前組件被銷毀的時候,因此,我們通過構造一個無界面的Fragment添加到當前的Activity中來實現監(jiān)聽當前組件的生命周期。
SimpleRxBus
SimpleRxBus就是按照上述想法來開發(fā)的一個事件總線庫,點我跳轉github,以下是使用簡介:
使用簡介
-
集成
implementation 'com.ladingwu.library:SimpleRxBus:0.1' // 需要v7的support包,如果項目中已經有了,則不用添加 implementation 'com.android.support:appcompat-v7:28.0.0' -
發(fā)送普通事件
RxBusUtils.post("filter_message",mesage); -
接收事件(自動取消訂閱)
// in Fragment or FragmentActivity RxBusUtils.receive(this,"filter_message", new RxBusReceiver<Object>() { @Override public void receive(Object message) { // handle this } }); -
發(fā)送粘性事件
RxBusUtils.postSticky("filter_sticky_message",message); -
接收粘性事件(自動取消訂閱)
// in Fragment or FragmentActivity RxBusUtils.receiveSticky(this,"filter_sticky_message", new RxBusReceiver<Object>() { @Override public void receive(Object message) { // handle this } }); -
特殊情況
//如果無法拿到Fragment/FragmentActivity的實例,則接收事件的時候,需要自行處理取消注冊的工作 Disposable disposable = RxBusUtils.receive("filter", new RxBusReceiver<Object>() { @Override public void receive(Object data) { // handle this } }); // 在合適的時機取消注冊 if (disposable != null && !disposable.isDisposed()) { disposable.dispose(); }