如何開發一個簡單好用的RxBus

作者:拉丁吳 https://www.jianshu.com/p/b5339f7bdfb3 已獲作者授權轉載

在Android開發中,事件總線的庫往往是開發必備的利器之一,我經歷的幾個開發項目,都無一例外的引用了事件總線的庫,因爲它能幫助我們非常簡單的實現組件之間的通信工作,極大的提高開發效率。

市面上EventBus,RxBus都是比較成熟的庫,爲什麼還是考慮自己開發一個呢?

主要還是用着不太順手,首先,Rxbus不支持粘性事件,這也就意味着Activity/Fragment之間的數據傳遞,還是需要寫很多Intent之類的代碼,降低了開發效率。其次,Rxbus,EventBus都需要手動註冊和註銷,稍顯麻煩。當然,最重要的因素是,通過RxJava開發一個RxBus也很方便。

因此在嘗試開發自己的RxBus之前,重點考慮下面兩點:

支持粘性事件 這是非常重要的,因爲有了粘性事件,我們可以解決activity/Fragment之間的消息傳遞,附帶的好處是,進程內的數據傳遞,可以打破Intent的大小限制。

簡單易用 這個是一個很重要的原則,參考rxbus,我們依然需要處理register(),unregister()方法,這就不是很友好了。一個成熟的rxbus應該能夠學會自己註冊和註銷,作爲使用者,我們只需要關心發送事件和接收事件。

如何支持粘性事件

RxJava天然的支持事件分發傳遞,比如,普通事件的傳遞,發送端我們可以直接使用PublishSubject,接收端則是普通的Observable即可,但是要支持粘性事件,我們需要考慮的東西就沒這麼簡單了,首先使用什麼樣的Subject能達成這樣的效果,是否有功能隱患或者性能隱患?

先來看看如何實現粘性事件的功能,我們熟知的Subject有四種:AsyncSubject,BehaviorSubject,PublishSubject,ReplaySubject,我們先一一解釋下這些東西

  • AsyncSubject:只在原始Observable完成後,發射來自原始Observable的最後一個值
  • BehaviorSubject:發射原始Observable最近發射的數據
  • PublishSubject:會把在訂閱發生的時間點之後來自原始Observable的數據發射給觀察者
  • ReplaySubject: 會發射所有來自原始Observable的數據給觀察者

從上面的介紹可以看出,AsyncSubject顯然不合適,PublishSubject看起來也不太合適,因爲它不會發送訂閱之前的消息,ReplaySubject和BehaviorSubject都能發送訂閱之前的消息。

ReplaySubject最大的問題就是它會把發送的歷史消息都存起來,但是我們其實並不需要存儲所有的事件,如果事件太多會帶來不必要的內存負擔,雖然ReplaySubject能提供方法設置內部最大存儲量來控制存儲大小,但是無法細粒度的定點清除事件,因此,我們先把它作爲一個性能較差備選的方案。

BehaviorSubject它只會存儲最近的一個事件,這樣不會有內存隱患,但是這個特性本身也會存在隱患。比如,在發送事件A和接收事件A之間的某個時間點,如果又發送了事件B 那麼,事件A就會被拋棄。接受者就永遠無法收到事件A了。這一點,從下圖中也很容易看得出來。

這個問題不容易被發現,開發人員能夠意識到這個問題還可以避免,但是如果多人協作,項目越來越複雜的情況下,我們就很難保證不會出現這樣的問題了。因此,BehaviorSubject也不是一個好的選擇。

其實,以上四個Subject都不是最好的選擇,最終還是決定自己緩存事件,並在合適的時機清除歷。

添加事件的時機是當我們需要post(event)的時候,就把事件添加進來,那麼何時清除事件呢?是消費完成之後就清除?顯然是不太合理的,參考Intent,在Activity中,可以多次獲取Intent,之後activity被銷燬了,intent纔會被銷燬,因此,我們清除事件在取消訂閱的時候,也就是組件被銷燬的時候。保證了我們可以多次多地獲取同樣額數據,

自動註冊註銷

在新的事件總線庫中,只有post(event)和receive(event),至於註冊和註銷我們基本不需要處理。除了我們所關心的,沒有任何多餘的工作。

框架會幫你自動註冊和註銷。註冊發生在準備接收數據的時候,即調用receive(Message)時,而註銷的時機就顯然是當前組件被銷燬的時候,因此,我們通過構造一個無界面的Fragment添加到當前的Activity中來實現監聽當前組件的生命週期。

SimpleRxBus

SimpleRxBus就是按照上述想法來開發的一個事件總線庫,地址:https://github.com/ladingwu/SimpleRxBusApplication,以下是使用簡介:

集成

implementation 'com.ladingwu.library:SimpleRxBus:0.1'
// 需要v7的support包,如果項目中已經有了,則不用添加
implementation 'com.android.support:appcompat-v7:28.0.0'  

發送普通事件

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

發送粘性事件

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

— — — END — — —

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章