前言
??在平時(shí)的開(kāi)發(fā)中,我們常常碰到這樣的需求,比如說(shuō),我們需要在一個(gè) Activity 中改變另一個(gè) Activity 中的數(shù)據(jù)。這個(gè)需求一般可以用接口或者用廣播的形式來(lái)實(shí)現(xiàn),但是實(shí)現(xiàn)起來(lái)步驟較多,比較麻煩。于是就出現(xiàn)了事件總線(xiàn)框架 EventbBus ,很好的解決了問(wèn)題,用起來(lái)也很方便。
??不過(guò)隨著技術(shù)的更新,現(xiàn)在很多的開(kāi)發(fā)都用起了 RxJava,同樣是基于訂閱者模式的 RxJava 是否也可以實(shí)現(xiàn)事件總線(xiàn)呢,答案是可以的,如果我們?cè)瓉?lái)的項(xiàng)目用到了 RxJava,現(xiàn)在又有事件總線(xiàn)的需求,就可以考慮使用 RxJava 來(lái)實(shí)現(xiàn),這樣項(xiàng)目就可以少一個(gè) EventBus 的依賴(lài),減小項(xiàng)目的體積,一舉兩得。
??下面介紹一下如何來(lái)搭建一個(gè)基于 RxJava 的事件總線(xiàn)。
實(shí)現(xiàn)
public class RxBus {
private final Relay<Object> mBus;
private RxBus() {
mBus = PublishRelay.create().toSerialized();
}
public static RxBus getInstance(){
return InstanceHolder.INSTANCE;
}
private static class InstanceHolder{
private static final RxBus INSTANCE = new RxBus();
}
public void post(Object o){
mBus.accept(o);
}
public <T> Observable<T> toObservable(Class<T> eventType){
return mBus.ofType(eventType);
}
}
??直接上代碼,沒(méi)錯(cuò),就這么幾行代碼,就可以實(shí)現(xiàn)事件總線(xiàn),要注意的是,這個(gè)類(lèi)中的百分之70的代碼是用來(lái)實(shí)現(xiàn)事件總線(xiàn)的單例,真正相關(guān)的方法只有 post(Object o) 和 toObservable(Class<T> eventType) 兩個(gè)。RxBus 并不是一個(gè)框架,而是一種使用 RxJava 實(shí)現(xiàn)事件總線(xiàn)的一種解決思路,實(shí)質(zhì)是交由 RxJava 去實(shí)現(xiàn)。
??重點(diǎn)介紹一下 RxBus 里 Relay 類(lèi)型的變量 mBus 和 post(Object o) 、 toObservable(Class<T> eventType) 兩個(gè)方法(好像就這三個(gè)需要介紹,哈哈)。
??看一下 Relay 類(lèi)型的源碼介紹。
/**
* Represents a Consumer and an Observable at the same time, allowing
* multicasting events from a single source to multiple child Observers.
* <p>All methods except {@link #accept} are thread-safe.
* Use {@link #toSerialized()} to make it thread-safe as well.
*
* @param <T> the item value type
*/
public abstract class Relay<T> extends Observable<T> implements Consumer<T> {
/** {@inheritDoc} */
??意思就是,Relay 類(lèi)型的對(duì)象,既是訂閱者又是被訂閱者,可以將事件從單一的源頭發(fā)送給多個(gè)訂閱者,利用這個(gè)特性,就可以用它來(lái)實(shí)現(xiàn)事件總線(xiàn)??梢钥吹皆诜椒?post(Object o) 中。
public void post(Object o){
mBus.accept(o);
}
??我們調(diào)用了他的 accept() 方法,這個(gè) accept() 就類(lèi)似于我們之前在使用 RxJava 時(shí)的 onNext() 方法,通知下游的訂閱者進(jìn)行相應(yīng)的處理操作。而 toObservable(Class<T> eventType) 方法。
public <T> Observable<T> toObservable(Class<T> eventType){
return mBus.ofType(eventType);
}
??我們可以看到,他的返回類(lèi)型是 Observable 類(lèi)型,我們就可以利用他返回的對(duì)象,進(jìn)行訂閱的操作。有張圖很形象。

??圖中的 PublishSubject 和 Relay 差不多,由于 RxJava 的特性,當(dāng)事件觸發(fā) onError 或者是 onComplete 的時(shí)候,訂閱關(guān)系就會(huì)終止,而在 RxBus 中,我們希望這個(gè)訂閱關(guān)系能一直保持下去,不然一個(gè)事件出現(xiàn)問(wèn)題后,其他的事件就無(wú)法處理,而 Relay 正是為了解決這個(gè)問(wèn)題才被設(shè)計(jì)出來(lái)的,所以在 RxBus 中我們用 Relay 而不是 Subject。事件一個(gè)個(gè)被 post 到這個(gè) Relay 對(duì)象上,然后再交由訂閱者處理。
??原理可能有點(diǎn)繞,直接展示如何使用可能會(huì)更好理解。
使用
??我們實(shí)現(xiàn)一下文章開(kāi)頭所講的需求,在一個(gè) Activity 中,改變另一個(gè) Activity 中的數(shù)據(jù)。
??第一個(gè)界面中有一個(gè)跳轉(zhuǎn)至第二個(gè)界面的按鈕,和一個(gè)展示數(shù)據(jù)的 TextView,第二個(gè)界面中有兩個(gè)按鈕,一個(gè)是向第一個(gè)界面發(fā)送消息一,一個(gè)是向第一個(gè)界面發(fā)送消息二。


??首先創(chuàng)建需要傳輸?shù)臄?shù)據(jù)的兩個(gè)類(lèi)型,這里我定義了兩個(gè)類(lèi)。
public class EventOne {
String msg;
public EventOne(String msg) {
this.msg = msg;
}
public String getMsg() {
return msg;
}
}
public class EventTwo {
String msg;
public EventTwo(String msg) {
this.msg = msg;
}
public String getMsg() {
return msg;
}
}
??在第二個(gè)界面中發(fā)送消息。
@OnClick({R.id.button2, R.id.button3})
public void onClick(View v) {
switch (v.getId()) {
default:
break;
case R.id.button2:
RxBus.getInstance().post(new EventOne("消息類(lèi)型一"));
break;
case R.id.button3:
RxBus.getInstance().post(new EventTwo("消息類(lèi)型二"));
break;
}
}
??在第一個(gè)界面中訂閱事件。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_rx1);
ButterKnife.bind(this);
//訂閱消息類(lèi)型一的事件
RxBus.getInstance().toObservable(EventOne.class)
.subscribe(new Consumer<EventOne>() {
@Override
public void accept(EventOne eventOne) throws Exception {
mTextView.setText("已接收" + eventOne.getMsg());
}
});
//訂閱消息類(lèi)型二的事件
RxBus.getInstance().toObservable(EventTwo.class)
.subscribe(new Consumer<EventTwo>() {
@Override
public void accept(EventTwo eventTwo) throws Exception {
mTextView.setText("已接收" + eventTwo.getMsg());
}
});
}
??在第二個(gè)界面中分別點(diǎn)擊發(fā)送消息后,第一個(gè)界面中的效果。


??可以看到第一個(gè)界面分別對(duì)兩個(gè)事件作出了反應(yīng)。我們通過(guò)第二個(gè) Activity
對(duì)第一個(gè) Activity 中的數(shù)據(jù)進(jìn)行了修改。RxBus 和 EventBus 的用法差不多,也就是創(chuàng)建要傳遞的事件類(lèi),在一個(gè)地方發(fā)送消息,在另一個(gè)地方接收處理消息。如果要傳遞不同的事件,就創(chuàng)建不同的事件類(lèi),用起來(lái)還是很方便的。
最后
??RxBus 和 EventBus 為我們提供了事件總線(xiàn)的方式,將一些操作進(jìn)行了解耦,方便了我們的操作,適當(dāng)?shù)氖褂每梢蕴岣呶覀兊木幊绦剩屛覀兛梢园阎攸c(diǎn)放在業(yè)務(wù)上而不是它的實(shí)現(xiàn)上,說(shuō)白了就是程序員喜歡偷懶,哈哈。
??關(guān)于 RxBus 和 EventBus 兩者之間的選擇,那就仁者見(jiàn)仁智者見(jiàn)智了,如果項(xiàng)目里有用到 RxJava 就可以考慮用一下 RxBus, 如果要用 EventBus 也是可以的,我看了一下 EventBus 的包,其實(shí)也不大。
??(這篇文章昨天晚上沒(méi)寫(xiě)完,今天早上在地鐵上用手機(jī)碼完了剩下的部分,等下到公司還要去改需求,又是喪喪的一天了( ¨? )
以上就是對(duì) RxBus 的介紹:)