RxBus主要用来处理应用程序间各个组件的通信,或者组件与组建之间的数据传递。(不用再像BroadcastReceiver一样,把数据封装到intent里面再传递出去了)。
首先,为什么叫他RxBus?其实我也不知道,当初我以为RxBus是一个封装好的库,直接拿过来用就好了。事实并非如此,我找了半天没找到现成的库,都是教你如何去通过RxJava来构造一个RxBus,既然这样,那我也就跟着他们做了。其实说到底,RxBus学的是一种思路,而并不是给你一个现成的库,然后直接去调用。
对RxJava还不熟悉的同学请学习我之前发的文章:RXJava学习最友好的系列资料,以下内容针对有RxJava基础的同学。
public enum RxBus {
INSTANCE;
private Subject<Object, Object> mRxBusObserverable = new SerializedSubject<>(PublishSubject.create());
public static void send(Object object) {
if (INSTANCE.mRxBusObserverable.hasObservers()) {
INSTANCE.mRxBusObserverable.onNext(object);
}
}
public static Observable<Object> toObserverable() {
return INSTANCE.mRxBusObserverable;
}
}
直接写成了一个单例(单例模式写法很多,不要纠结于这种写法,大家完全可以换一种写法),然后里面有两个方法,一个是send,一个是toObserable。send方法很简单,就是用来发送一条消息的,消息类型是Object类型,其实也就是说,可以发送任何消息。那么toObserable是干嘛的呢?就是用来订阅消息的,如果不订阅的话,send方法就没有任何意义了。
send方法是static类型的,所以在程序的任何地方都可以调用。调用之后,代表一条信息发出去了,只要是订阅过的人,都可以接收到。
toObserverable也是static类型的,所以在程序的任何地方都可以调用。调用之后,就说明订阅成功了。如果我这个时候send一下,那就会接收到消息了。
我们来看一下如何使用这个类。
我们先调用toObserverable这个方法,还是那句话,如果不订阅的话,send就没有意义了。那我们什么时候去订阅呢?谁去订阅呢?订阅之后要干嘛呢?看代码便知:
public abstract class BaseActivity extends AppCompatActivity {
private Subscription subscription;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initRxBus(setOnNext());
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindRxBus();
}
private Action1<Object> setOnNext() {
return new Action1<Object>() {
@Override
public void call(Object o) {
doOnNext(o);
}
};
}
protected abstract void doOnNext(Object o);
private void initRxBus(final Action1<Object> onNext) {
if (onNext != null) {
subscription = RxBus.toObserverable()
.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(onNext);
}
}
private void unbindRxBus() {
if (subscription != null) {
subscription.unsubscribe();
}
}
}
从整体上来看,onCreate方法初始化RxBus,onDestory方法解绑RxBus。换句话说,其实就是在onCreate中订阅一下,在onDestory中取消订阅,意思就是说,MainActivity已经开始关注RxBus了,RxBus只要一有动静,MainActivity就能马上知道。取消订阅是为了防止程序内存泄漏。取消订阅的代码很简单,我不多解释。我们主要来看一下订阅的代码。
initRxBus(setOnNext());
先看一下initRxBus(final Aciton1<Object> onNext)这个方法,其实里面就是简单调用了RxBus的订阅方法,然后用Schedulers切换了线程,最后subscribe一下。
再来看一下setOnNext( )方法,返回值是Action1,而里面的代码我就直接return了一个Action1,但是我把call(Object o)用一个抽象方法分出去了,这么做有一个好处,就是代码简洁一些。这里面可能有一点绕,大家还是得多看看。那这个方法到底是干嘛用的???肯定有用啊,不然写出来干嘛!!!如果你这个时候调用一下RxBus.send方法,你会发现,doOnNext是会被执行的,而且参数o就是send方法传过来的参数。这么搞的话,是不是比BroadcastReceiver简单多了!如果你还没明白,那我们来写个例子吧。
这个BaseActivity是抽象的,所以我们再写一个Activity来继承它,看一下我是怎么写的。
public class MainActivity extends BaseActivity {
private final String TAG = MainActivity.class.getSimpleName();
@Override
protected void doOnNext(Object o) {
//接收到全局广播之后在这里处理相关的业务逻辑
Log.d(TAG, "订阅者:" + TAG + "->接收到的消息:" + o.toString());
}
}
public class MainActivity2 extends BaseActivity {
private final String TAG = MainActivity2.class.getSimpleName();
@Override
protected void doOnNext(Object o) {
//接收到全局广播之后在这里处理相关的业务逻辑
Log.d(TAG, "订阅者:" + TAG + "->接收到的消息:" + o.toString());
}
}
写了两个Activity,其他不相关的代码我已经删掉了,所以代码看起来很简洁。这两个Activity都对doOnNext进行了处理。这个时候我们要定义一个按钮,当点击按钮的时候,就发送一条信息,这个按钮的点击事件是这么写的:
@Override
public void onClick(View v) {
RxBus.send(new Random().nextInt());
}
代码很简单,就是发送一个随机的数字。现在万事俱备,只欠东风,我们要让程序跑起来。怎么跑呢?我是这么操作的:
public class MainActivity extends BaseActivity {
private final String TAG = MainActivity.class.getSimpleName();
@Override
protected void doOnNext(Object o) {
//接收到全局广播之后在这里处理相关的业务逻辑
Log.d(TAG, "订阅者:" + TAG + "->接收到的消息:" + o.toString());
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
……
……
……
//启动MainActivity2
Intent intent = new Intent(this, MainActivity2.class);
startActivity(intent);
}
}
进入到MainActivity之后,立马启动MainActivity2,这样就能保证两个Activity同时存在了。我们这个时候再来看一下MainActivity2的代码:
public class MainActivity2 extends BaseActivity {
private final String TAG = MainActivity.class.getSimpleName();
@Override
protected void doOnNext(Object o) {
//接收到全局广播之后在这里处理相关的业务逻辑
Log.d(TAG, "订阅者:" + TAG + "->接收到的消息:" + o.toString());
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
……
……
……
findViewById(R.id.button1).setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
RxBus.send(new Random().nextInt());
}
});
}
}
代码也很简单,就是每次点击按钮的时候,都会发送一个随机数字,只要是订阅过的人,都可以接收到这条消息。我运行了一下程序,看一下运行结果:
可以看到,两个订阅者都收到消息了。那现在尝试去更新一下UI,代码要稍微改动一下,改成这样:
public class MainActivity extends BaseActivity {
private TextView rxbus_tv;
@Override
protected void doOnNext(Object o) {
if (rxbus_tv != null) {
rxbus_tv.setText("接收到消息->" + o.toString());
}
}
@Override
protected void onCreate() {
……
……
……
rxbus_tv = (TextView) findViewById(R.id.activity_rxbus1_tv);
findViewById(R.id.activity_rxbus1_btn).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(context, TestRxActivity2.class);
startActivity(intent);
}
});
}
}
public class MainActivity2 extends BaseActivity {
private TextView rxbus_tv;
@Override
protected void doOnNext(Object o) {
if (rxbus_tv != null) {
rxbus_tv.setText("接收到消息->" + o.toString());
}
}
@Override
protected void onCreate() {
……
……
……
rxbus_tv = (TextView) findViewById(R.id.activity_rxbus2_tv);
findViewById(R.id.activity_rxbus2_btn).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
RxBus.send(new Random().nextInt());
}
});
}
}
没有太多的改动,就是在doOnNext方法里面把Log打印语句换成了setText。看一下运行效果:
当在MainActivity2中发送一条消息的时候,MainActivity1和MainActivity2都可以接收到并且能够去更新UI,是不是感觉很方便。
那么这个时候有的同学就要问了,我只想让MainActivity1去接收我的消息并且更新UI,我不想让MainActivity2去更新,怎么办呢?
其实这个问题很好解决的。我们只需要在相应的Activity中加一些过滤条件就好了,问题是,怎么加过滤条件呢?
这里我先封装一个bean对象,包含三个属性,一个是from,一个是to,还有一个是content,具体代码是这样的:
public class RxBusBean {
private String from;
private String to;
private String content;
public RxBusBean() {
}
public RxBusBean(String from, String to, String content) {
this.from = from;
this.to = to;
this.content = content;
}
public String getFrom() {
return from;
}
public void setFrom(String from) {
this.from = from;
}
public String getTo() {
return to;
}
public void setTo(String to) {
this.to = to;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
其实理解起来就像寄快递一样,有寄货方姓名,收货方姓名和具体内容。
使用的时候可以封装成Gson,这样比较简单。发送消息的时候代码要改成这样:
RxBusBean bean = new RxBusBean();
bean.setFrom("MainActivity2");
bean.setTo("MainActivity1");
bean.setContent(new Random().nextInt() + "");
Gson gson = new Gson();
RxBus.send(gson.toJson(bean));
接收消息的时候要改成这样:
Gson gson = new Gson();
RxBusBean bean = gson.fromJson(o.toString(), RxBusBean.class);
if (bean.getTo().equals("MainActivity1")) {
rxbus_tv.setText("接收到消息->" + bean.getContent());
}
这样处理之后,只有MainActivity1可以对消息进行处理。虽然MainActivity2可以接收到消息,但是没办法对消息进行处理。看一下效果图:
博客的代码不是很完整,重点讲解思路,完整的代码在这里:
http://gitlab.alibaba-inc.com/sihua.hsh/RXBus
工程中引用这个库和相关测试例子,使用:
compile 'com.yunos.tv.androidlib:rxbus:1.0.1-SNAPSHOT'
repositories {
maven {
url "http://mvnrepo.alibaba-inc.com/nexus/content/repositories/snapshots"
}
}