简单封装Rxbus
在组件化的工程中,不同组件通常位于不同的模块中,实现组件间的通信有多种方案,最常用的是Eventbus,但是如果项目中有使用Rxjava的话,我们可以使用RxJava的响应式编程替换掉Eventbus,接下来我们将逐步探索RxBus的封装。
1. 单一的订阅关系
首先看一种封装,如下:
public enum RxBus {
INSTANCE;
// 发射器
private ObservableEmitter mEmitter;
private Observable mObservable = Observable.create (emitter -> {
mEmitter = emitter;
emitter.onNext (new Object ());
});
public void post(Object obj){
mEmitter.onNext (obj);
}
public <T> Observable<T> toObservable(Class<T> clazz){
// 只处理clazz类型的数据
return mObservable.ofType (clazz);
}
}
使用方法如下:
事件发送方:
ModuleAEvent event = new ModuleAEvent ();
event.setName ("hello");
RxBus.INSTANCE.post (event);
接收方:
RxBus.INSTANCE.toObservable (ModuleAEvent.class).subscribe (
moduleAEvent -> {
Log.d (TAG, "ModuleAEvent name is: " + moduleAEvent.getName ());
},
throwable -> {
Log.d (TAG, "error!");
}
);
ModuleAEvent为定义的事件类型,一个简单的javabean:
public class ModuleAEvent {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
由于是全局使用的,所以使用一个枚举单例。如果使用,会发现这种方式只能支持一个订阅者,也就是一个组件发出的事件只能被一个组件接收,不支持多个组件订阅同一个事件。显然这不能满足要求,我们需要寻找更好的方法。
2. 多个订阅者
查看RxJava的文档可以发现一个名为Subject的抽象类,它的描述如下:
注释明确指出了允许单一事件源向多个观察者发送多个事件(我理解的这里的多个事件指的是多个onNext()方法的执行), 开来这就是要找的类了。这是一个抽象类,他有多个实现:
所有的子类都对外隐藏了构造方法,但是提供了一个create()静态方法拿到相应的实例。所以我们用其中任意一个公开的类拿到实例,进而封装RxBus,比如我选用了PublishSubject这个子类,那么我的RxBus可以这样封装:
public enum RxBus {
INSTANCE;
private Subject mSubject = PublishSubject.create ();
public void post(Object obj){
mSubject.onNext (obj);
}
public <T> Observable<T> toObservable(Class<T> clazz){
// 只处理clazz类型的数据
return mSubject.ofType (clazz);
}
}
测试后发现一个事件确实可以被多个订阅者同时订阅。
3. 粘性事件的支持
粘性事件指的是订阅者在事件发出之后才和事件建立订阅关系,有时我们同样希望这些事件不被错过,所以这些事件应该在建立订阅关系的时候发送给订阅者,这个就是粘性事件。上面封装的RxBus是不能满足这种需要的,如何更改呢?
其实Subject的几个实现类中有一个子类ReplaySubject。查看文档会发现:
向现在和以后的订阅者回应事件,显然就是这个了,下面的示例也证实了这一点:
所以,支持粘性事件的RxBus封装如下:
public enum RxBus {
INSTANCE;
private Subject mSubject = ReplaySubject.create ();
public void post(Object obj){
mSubject.onNext (obj);
}
public <T> Observable<T> toObservable(Class<T> clazz){
// 只处理clazz类型的数据
return mSubject.ofType (clazz);
}
}
这里只是简单的实现了功能,更多的细节,比如数据流的及时断开等,可以根据具体的应用场景再进一步封装。