放棄RxBus,擁抱RxJava(一):爲何避免使用EventBus/RxBus | 掘金技術徵文

這一系列文章原本我發表在簡書。最近開始轉移到掘金。之後也會在掘金髮表(慢慢拋棄簡書了應該,掘金的技術環境確實比簡書好些)。javascript

EventBus和Otto在以前做爲Android組件間通訊工具,簡單方便十分受歡迎,可是也很是容易Abuse。大概有以下幾個缺點:java

  • 因爲是Event,在發佈Event的時候就要作好準備可能並無人接受這個Event, Subscribe的時候也要作好準備可能永遠不會收到Event。Event不管順序仍是時間上都某種程度上不太可控。若是你將數據寄託在Event上而後就直接在Android其餘生命週期方法中直接使用這個數據或成員變量。那麼頗有可能你會獲得NPE。
  • EventBus看似將你的程序解耦,可是又有些過了。咱們經常使用EventBus傳數據,這已是Dependency級別的數據而不是一個能夠被解耦出來的模塊。這樣就形成了過多EventBus的代碼會形成代碼結構混亂,難以測試和追蹤,違背瞭解耦的初衷。這時若是有意或無心的形成了Nested Event。那狀況會更糟。

因爲EventBus的種種缺點,以及後面RxJava的出現。不少人都開始使用RxJava來取代EventBus。甚至Otto的官方介紹裏都寫到:android

Deprecated!

This project is deprecated in favor of RxJava and
RxAndroid. These projects permit the same event-driven
programming model as Otto, but they’re more capable and offer better control of threading.git

If you’re looking for guidance on migrating from Otto to Rx, this post
is a good start.github

連接是一個教你怎麼使用RxJava來本身手動寫一個RxBus來代替EventBus的文章。雖然看起來是在用RxJava。可是實際上卻仍然在用EventBus。甚至這個封裝其實也並無GreenRobot或者Otto來的好。
咱們看看Jake Wharton對RxBus的評價:
編程


我想"RxBus"惟一的好處就是他是一個Rx的入門毒品。不然的話,你要麼就不是在用Rx,要麼你須要更加慣用的Rx資源 (渣翻譯見諒)

再來一個GitHub的:
安全

subscribeActual部分咱們先不考慮。然而Jake指出最好不要使用Relay來「從新發明」Event Bus.app

這裏看圖說話:
Jake Wharton在GOTO 2016 上的講座中提到,咱們正常的Android編程是這樣的:
ide


咱們像一箇中間人同樣。
而使用RxJava。 咱們的結構,更像這樣

咱們使用RxJava來直接把組件相連,對所接受到的數據做出反應,所謂的 "Reactive"。
而使用Eventbus? Jake 沒說, 我本身畫一個:


咱們做爲一箇中間人,傳遞消息。EventBus做爲另外一箇中間人。幫咱們傳遞消息。(這也就是所謂的「看似解耦」)

再打個比方,雖然咱們將EventBus翻譯成時間總線,可是其實總線就是Bus也就是公交車。而RxJava更像一個專車,Uber或者滴滴。他直接連接你的兩個或多個須要通訊的類。傳輸數據,固然你能夠作一個很大的專車,穿梭在全部類之間,也就是所謂的RxBus。因此在這裏爲何放棄RxBus也就不言而喻了不是?工具

那麼,問題來了?

怎樣纔是正確(正常?)的RxJava使用方式?

其實Jake 也在GitHub的討論上給出了一個答案:

因此應該是,每當你想發佈一個Event在EventBus時,直接暴露一個Observable出來。每當你想接受一個Event時,找到這個Observable而且Subscribe他。

這樣作的好處是什麼?

  • 目標和地點都很明確。你的Subscriber明確的知道他Subscribe的是誰,並且明確的知道我須要做出什麼反應。這也正是RxJava的核心「響應式編程」。
  • 因爲使用了Observable,對於異常處理將會很是方便。並且還有功能強大全面的Operator來輔助你。
  • 雖然看起來耦合性有所增長。可是這是必要的,上面也說過,EventBus雖然在代碼上看似解耦。其實他們仍是聯繫在一塊兒的。而咱們這樣直接暴露Observable給須要的其餘類,這完成了1 -> 1/N的連接,而不須要EventBus這個中間人來傳遞消息/事件,並且保證咱們須要的事件必定會直接到達。

咱們來舉個例子

上下兩個Fragment,上面的一個EditText,下面的一個TextView。上面的EditText變化的時候下面的TextView也跟着變化。

先把EditText的TextChangedListener封裝在Observable裏:

stringObservable = Observable.create(e -> editText.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {

            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                e.onNext(s.toString());
            }

            @Override
            public void afterTextChanged(Editable s) {

            }
        }));

/** *** */
    //Expose Observable
    public Observable<String> getEditTextObservable() {
        return stringObservable;
    }複製代碼

不習慣本身封裝可使用RxBinding :

stringObservable = RxTextView.textChangeEvents(editText)
                                     .map(event -> event.text().toString());複製代碼

再從咱們的TextViewFragment中 取到這個封裝好的Observable:

@Override
    public void onStart() {
        super.onStart();
        FragmentEditText fragment = (FragmentEditText) getFragmentManager().findFragmentByTag(FragmentEditText.TAG);
        if(fragment != null){
            fragment.getStringObservable().subscribe(s -> textView.setText(s));
        }
    }複製代碼

來看看效果:

固然,這裏還有個問題

  • 因爲咱們將editText封裝在Observable裏,不管是create()方法仍是使用RxBinding,都會持有這個View的強引用。形成內存泄漏。因此咱們必定要在最後加入dispose()方法來釋放。因此我推薦使用RxBinding,他已經幫咱們在dispose()方法裏寫好了解除Listener的方法。
  • 由於並無使用publish操做符,致使多個Subscriber的時候仍是有些許問題。能夠考慮直接加入.share().

總結:

前幾天我在Reddit上看到一我的的回覆:

I think EventBus on android is popular because people don't know how to share a java object reference between android components like a Fragment and an Activity, or 2 Activities and so on. So basically I think people don't know how 2 Activites can observe the same object for data changes which I think comes from the fact that we still don't know how to architect our apps properly.

我認爲 EventBus在Android上火爆的緣由是人們不知道怎麼去在Android組件,例如Activity/Fragment之間共享一個Java對象的引用。

這個回覆能夠說應該是觸到了不少人的痛點。不少狀況咱們用EventBus僅僅是不知道如何在多個Fragment/Activity之間共享一個對象。EventBus的作法是在Bus裏登記全部的接受者。這點在RxJava裏相似,Subject/ConnectableObservable 都有相似的功能。但問題是EventBus做爲一個全局Bus,各類不一樣類型的事件管理會很麻煩(雖然EventBus把這些事給你作好了,RxBus要本身弄)。咱們有了RxJava徹底能夠避免不一樣事件的管理。相同事件封裝成對應Observable,根據需求選擇訂閱。這樣保持了類型安全,提升了性能,邏輯更清晰。

想想,本身使用EventBus是否是也是這個緣由呢?

掘金技術正文

相關文章
相關標籤/搜索