前言
以前在项目中使用EventBus,来进行事件通知与订阅。
现在使用RxJava实现一个发布/订阅事件总线:RxBus。
rxjava 1.x实现
- RxBus代码:
/**
* desc : 利用 PublishSubject的特性:与普通的Subject不同,在订阅时并不立即触发订阅事件,
* 而是允许我们在任意时刻手动调用onNext(),onError(),onCompleted来触发事件。
* author : stone
* email : aa86799@163.com
* time : 24/04/2017 11 20
*/
public class RxBus {
private ConcurrentHashMap<Object, List<Subject>> subjectMapper = new ConcurrentHashMap<>();
private RxBus() {
}
private static class Holder {
private static RxBus instance = new RxBus();
}
public static RxBus getInstance() {
return Holder.instance;
}
public <T> Observable<T> register(@NonNull Class<T> clz) {
return register(clz.getName());
}
public <T> Observable<T> register(@NonNull Object tag) {
List<Subject> subjectList = subjectMapper.get(tag);
if (null == subjectList) {
subjectList = new ArrayList<>();
subjectMapper.put(tag, subjectList);
}
Subject<T, T> subject = PublishSubject.create();
subjectList.add(subject);
//System.out.println("注册到rxbus");
return subject;
}
public <T> void unregister(@NonNull Class<T> clz, @NonNull Observable observable) {
unregister(clz.getName(), observable);
}
public void unregister(@NonNull Object tag, @NonNull Observable observable) {
List<Subject> subjects = subjectMapper.get(tag);
if (null != subjects) {
subjects.remove(observable);
if (subjects.isEmpty()) {
subjectMapper.remove(tag);
//System.out.println("从rxbus取消注册");
}
}
}
public void post(@NonNull Object content) {
post(content.getClass().getName(), content);
}
public void post(@NonNull Object tag, @NonNull Object content) {
List<Subject> subjects = subjectMapper.get(tag);
if (!subjects.isEmpty()) {
for (Subject subject: subjects) {
subject.onNext(content);
}
}
}
}
几个关键方法:
register —— 由tag,生成一个subject List,同时利用PublishSubject创建一个Subject并返回,它同时也是Observable的子类。
unregister —— 移除tag对应subject List 中的Observable。若subject List为空,也将被移除。
post —— 遍历tag对应subject List 中的Subject,执行onNext()。这里实际执行的是观察者Observer的onNext(),Subject的定义:public abstract class Subject<T, R> extends Observable<R> implements Observer<T>。
- 测试代码:
/*
rxbus
*/
Observable<String> observable = RxBus.getInstance().register(String.class);
observable.map(s -> {
try {
int v = Integer.valueOf(s);
System.out.println("map变换成功, source = " + s);
return v;
} catch (Exception e) {
System.out.println("map变换失败, source = " + s);
return s;
}
}).subscribe(value -> {
System.out.println("订阅 " + value);
});
RxBus.getInstance().post("888");
RxBus.getInstance().post("发发发");
RxBus.getInstance().unregister(String.class, observable);
这里比较有意思的是,使用了lambda表达式。在map变换时,如果将字符串转成Integer,没有问题就返回整型;若报异常,就返回String型。同样的,在最终订阅时,value参数的类型也是由map变换来决定的。
rxjava 2.x实现
在 RxJava 2.0 之后,io.reactivex.Observable中没有进行背压处理了,如果有大量消息堆积在总线中来不及处理会产生MissingBackpressureException或者OutOfMemoryError,有新的类io.reactivex.Flowable 专门针对背压问题。
无背压处理的Observable实现,跟rxjava1.x中一样,使用PublishSubject来实现。
要实现有背压的2.x版,使用FlowableProcessor的子类PublishProcessor 来产生 Flowable,以实现 RxBus。
- RxBus代码:
public class RxBus {
private final FlowableProcessor<Object> mBus;
private RxBus() {
mBus = PublishProcessor.create().toSerialized();
}
private static class Holder {
private static RxBus instance = new RxBus();
}
public static RxBus getInstance() {
return Holder.instance;
}
public void post(@NonNull Object obj) {
mBus.onNext(obj);
}
public <T> Flowable<T> register(Class<T> clz) {
return mBus.ofType(clz);
}
public void unregisterAll() {
//会将所有由mBus 生成的 Flowable 都置 completed 状态 后续的 所有消息 都收不到了
mBus.onComplete();
}
public boolean hasSubscribers() {
return mBus.hasSubscribers();
}
}
- 测试代码:
Flowable<Integer> f1 = RxBus.getInstance().register(Integer.class);
f1.subscribe(value -> System.out.println("订阅f1消息 .. " + value));
RxBus.getInstance().post(999);
参考
www.cnblogs.com/tiantianbyc… 《[Android]基于RxJava、RxAndroid的EventBus实现》
johnnyshieh.github.io/android/201… 《RxJava 2 版本的 Rxbus》