EventBus和Otto在之前作為Android組件間通信工具,簡單方便十分受歡迎,但是也非常容易Abuse。大概有如下幾個缺點:
- 由于是Event,在發布Event的時候就要做好準備可能并沒有人接受這個Event, Subscribe的時候也要做好準備可能永遠不會收到Event。Event無論順序還是時間上都某種程度上不太可控。如果你將數據寄托在Event上然后就直接在Android其他生命周期方法中直接使用這個數據或成員變量。那么很有可能你會得到NPE。
- EventBus看似將你的程序解耦,但是又有些過了。我們常常使用EventBus傳數據,這已經是Dependency級別的數據而不是一個可以被解耦出來的模塊。這樣就造成了過多EventBus的代碼會造成代碼結構混亂,難以測試和追蹤,違背了解耦的初衷。這時如果有意或無意的造成了Nested Event。那情況會更糟。
由于EventBus的種種缺點,以及后面RxJava的出現。很多人都開始使用RxJava來取代EventBus。甚至Otto的官方介紹里都寫到:
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.
If you’re looking for guidance on migrating from Otto to Rx, this post
is a good start.
鏈接是一個教你怎么使用RxJava來自己手動寫一個RxBus來代替EventBus的文章。雖然看起來是在用RxJava。但是實際上卻仍然在用EventBus。甚至這個封裝其實也并沒有GreenRobot或者Otto來的好。
我們看看Jake Wharton對RxBus的評價:
我想"RxBus"唯一的好處就是他是一個Rx的入門毒品。否則的話,你要么就不是在用Rx,要么你需要更加慣用的Rx資源 (渣翻譯見諒)
再來一個GitHub的:
subscribeActual部分我們先不考慮。然而Jake指出最好不要使用Relay來“重新發明”Event Bus.
這里看圖說話:
Jake Wharton在GOTO 2016 上的講座中提到,我們正常的Android編程是這樣的:
我們像一個中間人一樣。
而使用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().
具體我們如何講常用的數據/Callback封裝到Observable中。我會在接下來的文章中寫到。
> [第二篇鏈接](http://www.lxweimin.com/p/d2df6bceeff9)