详解用RxJava实现事件总线(Event Bus)
作者:YoKey 发布时间:2022-02-13 16:43:18
目前大多数开发者使用EventBus或者Otto作为事件总线通信库,对于RxJava使用者来说,RxJava也可以轻松实现事件总线,因为它们都依据于观察者模式。
不多说,上代码
/**
* RxBus
* Created by YoKeyword on 2015/6/17.
*/
public class RxBus {
private static volatile RxBus defaultInstance;
private final Subject<Object, Object> bus;
// PublishSubject只会把在订阅发生的时间点之后来自原始Observable的数据发射给观察者
public RxBus() {
bus = new SerializedSubject<>(PublishSubject.create());
}
// 单例RxBus
public static RxBus getDefault() {
if (defaultInstance == null) {
synchronized (RxBus.class) {
if (defaultInstance == null) {
defaultInstance = new RxBus();
}
}
}
return defaultInstance ;
}
// 发送一个新的事件
public void post (Object o) {
bus.onNext(o);
}
// 根据传递的 eventType 类型返回特定类型(eventType)的 被观察者
public <T> Observable<T> toObservable (Class<T> eventType) {
return bus.ofType(eventType);
// 这里感谢小鄧子的提醒: ofType = filter + cast
// return bus.filter(new Func1<Object, Boolean>() {
// @Override
// public Boolean call(Object o) {
// return eventType.isInstance(o);
// }
// }) .cast(eventType);
}
}
注:
1、Subject同时充当了Observer和Observable的角色,Subject是非线程安全的,要避免该问题,需要将 Subject转换为一个 SerializedSubject ,上述RxBus类中把线程非安全的PublishSubject包装成线程安全的Subject。
2、PublishSubject只会把在订阅发生的时间点之后来自原始Observable的数据发射给观察者。
3、ofType操作符只发射指定类型的数据,其内部就是filter+cast(这里非常感谢@小鄧子 的提醒)
public final <R> Observable<R> ofType(final Class<R> klass) {
return filter(new Func1<T, Boolean>() {
@Override
public final Boolean call(T t) {
return klass.isInstance(t);
}
}).cast(klass);
}
filter操作符可以使你提供一个指定的测试数据项,只有通过测试的数据才会被“发射”。
cast操作符可以将一个Observable转换成指定类型的Observable。
分析:
RxBus工作流程图
1、首先创建一个可同时充当Observer和Observable的Subject;
2、在需要接收事件的地方,订阅该Subject(此时Subject是作为Observable),在这之后,一旦Subject接收到事件,立即发射给该订阅者;
3、在我们需要发送事件的地方,将事件post至Subject,此时Subject作为Observer接收到事件(onNext),然后会发射给所有订阅该Subject的订阅者。
对于RxBus的使用,就和普通的RxJava订阅事件很相似了。
先看发送事件的代码:
RxBus.getDefault().post(new UserEvent (1, "yoyo"));
userEvent是要发送的事件,如果你用过EventBus, 很容易理解,UserEvent的代码:
public class UserEvent {
long id;
String name;
public UserEvent(long id,String name) {
this.id= id;
this.name= name;
}
public long getId() {
return id;
}
public String getName() {
return name;
}
}
再看接收事件的代码:
// rxSubscription是一个Subscription的全局变量,这段代码可以在onCreate/onStart等生命周期内
rxSubscription = RxBus.getDefault().toObserverable(UserEvent.class)
.subscribe(new Action1<UserEvent>() {
@Override
public void call(UserEvent userEvent) {
long id = userEvent.getId();
String name = userEvent.getName();
...
}
},
new Action1<Throwable>() {
@Override
public void call(Throwable throwable) {
// TODO: 处理异常
}
});
最后,一定要记得在生命周期结束的地方取消订阅事件,防止RxJava可能会引起的内存泄漏问题。
@Override
protected void onDestroy() {
super.onDestroy();
if(!rxSubscription.isUnsubscribed()) {
rxSubscription.unsubscribe();
}
}
这样,一个简单的Event Bus就实现了!如果你的项目已经开始使用RxJava,也许可以考虑替换掉EventBus或Otto,减小项目体积。
RxBus、EventBus因为解耦太彻底,滥用的话,项目可维护性会越来越低;一些简单场景更推荐用回调、Subject来代替事件总线。
来源:http://www.jianshu.com/p/ca090f6e2fe2


猜你喜欢
- 本文实例讲述了Android开发实现SubMenu选项菜单和子菜单。分享给大家供大家参考,具体如下:简介:SubMenu:代表一个子菜单,包
- JAVA IDEA 打开assert 设置概念(此处为借鉴前辈们的讲解)断言(Assertion)是Java中一条语句,包含一个布尔表达式,
- mybatis-plus 新增/修改 自动填充指定字段1.需要修改的字段在模型类上添加@TableField(fill = FieldFil
- 学习大佬们开发安全小工具,打包jar解决错误: 找不到或无法加载主类 main1 Maven方式遇到报错”找不到或无法加载主类 main“解
- 一.前言Unity3D是如今最火爆的游戏开发引擎,它可以让我们能轻松创建诸如三维视频游戏、建筑可视化、实时三维动画等类型的互动内容。它支持2
- Controller代码package com.keafmd.controller;import org.springframework.w
- 方式一 通过Map.keySet使用iterator遍历@Testpublic void testHashMap1() { Map<I
- 这篇文章主要介绍了SpringBoot FreeWorker模板技术解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考
- 提到输入参数的基本验证(非空、长度、大小、格式…),在以前我们还是通过手写代码,各种if、else、StringUtils.isEmpty、
- 请求路径匹配路由在spring中,当一个请求过来的时候会做路径匹配,下面我们就从源码层面分析一下路径匹配。示例:@RequestMappin
- 本文实例展示C#实现过滤html标签,汉字间空格,制表符,并保留a标签的方法。分享给大家供大家参考之用。具体方法如下:可以在公共类如Comm
- 一 ,定义接口和抽象类interface IPerson{ //获取名字 fun getName():String //获取身份证ID fu
- Android 显示刷新频率android11-release 开发者选项->显示刷新频率packages/apps/Settings
- Quartz与Spring集成方式:1.MethodInvokeJobDetailFactoryBean2.JobDetailBean下面分
- 简介现在市面上的apk只要涉及用户中心都会有头像,而且这个头像也是可自定义的,有的会采取读取相册选择其中一张作为需求照片,另一种就是调用系统
- Lucene从今天开始,我们要开始介绍Lucene中索引构建的流程。因为索引构建的逻辑涉及到的东西非常多,如果从构建入口IndexWrite
- 最近博主开始在项目中实践MVP模式,却意外发现内存泄漏比较严重,但却很少人谈到这个问题,促使了本文的发布,本文假设读者已了解MVP架构。MV
- Double转化为String时的保留位数及格式有时需要将程序中的数据写入到文件中进行保存,这时候就涉及到数据的字符串格式问题。下面介绍Do
- 方法一: view.post(Runnable runnable)使用 view 对象,调用 post 方法即可在主线程中执行里边的代码,p
- 环境变量这个概念不陌生, 就是操作系统的环境变量。系统变量就是java本身维护的变量。 通过 System.getProperty 的方式获