RxBus—使用RxJava实现的EventBus

前言

  在平时的开发中,我们常常碰到这样的需求,比如说,我们需要在一个 Activity 中改变另一个 Activity 中的数据。这个需求一般可以用接口或者用广播的形式来实现,但是实现起来步骤较多,比较麻烦。于是就出现了事件总线框架 EventbBus ,很好的解决了问题,用起来也很方便。
  不过随着技术的更新,现在很多的开发都用起了 RxJava,同样是基于订阅者模式的 RxJava 是否也可以实现事件总线呢,答案是可以的,如果我们原来的项目用到了 RxJava,现在又有事件总线的需求,就可以考虑使用 RxJava 来实现,这样项目就可以少一个 EventBus 的依赖,减小项目的体积,一举两得。
  下面介绍一下如何来搭建一个基于 RxJava 的事件总线。

实现

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);
    }
}

  直接上代码,没错,就这么几行代码,就可以实现事件总线,要注意的是,这个类中的百分之70的代码是用来实现事件总线的单例,真正相关的方法只有 post(Object o) 和 toObservable(Class eventType) 两个。RxBus 并不是一个框架,而是一种使用 RxJava 实现事件总线的一种解决思路,实质是交由 RxJava 去实现。
  重点介绍一下 RxBus 里 Relay 类型的变量 mBus 和 post(Object o) 、 toObservable(Class eventType) 两个方法(好像就这三个需要介绍,哈哈)。
  看一下 Relay 类型的源码介绍。

/**
 * 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 类型的对象,既是订阅者又是被订阅者,可以将事件从单一的源头发送给多个订阅者,利用这个特性,就可以用它来实现事件总线。可以看到在方法 post(Object o) 中。

    public void post(Object o){
        mBus.accept(o);
    }

  我们调用了他的 accept() 方法,这个 accept() 就类似于我们之前在使用 RxJava 时的 onNext() 方法,通知下游的订阅者进行相应的处理操作。而 toObservable(Class eventType) 方法。

    public <T> Observable<T> toObservable(Class<T> eventType){
        return mBus.ofType(eventType);
    }

  我们可以看到,他的返回类型是 Observable 类型,我们就可以利用他返回的对象,进行订阅的操作。有张图很形象。

  图中的 PublishSubject 和 Relay 差不多,由于 RxJava 的特性,当事件触发 onError 或者是 onComplete 的时候,订阅关系就会终止,而在 RxBus 中,我们希望这个订阅关系能一直保持下去,不然一个事件出现问题后,其他的事件就无法处理,而 Relay 正是为了解决这个问题才被设计出来的,所以在 RxBus 中我们用 Relay 而不是 Subject。事件一个个被 post 到这个 Relay 对象上,然后再交由订阅者处理。
  原理可能有点绕,直接展示如何使用可能会更好理解。

使用

  我们实现一下文章开头所讲的需求,在一个 Activity 中,改变另一个 Activity 中的数据。
  第一个界面中有一个跳转至第二个界面的按钮,和一个展示数据的 TextView,第二个界面中有两个按钮,一个是向第一个界面发送消息一,一个是向第一个界面发送消息二。
第一个界面

第二个界面

  首先创建需要传输的数据的两个类型,这里我定义了两个类。

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;
    }
}

  在第二个界面中发送消息。

    @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("消息类型一"));
                break;
            case R.id.button3:
                RxBus.getInstance().post(new EventTwo("消息类型二"));
                break;
        }
    }

  在第一个界面中订阅事件。

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_rx1);
        ButterKnife.bind(this);

        //订阅消息类型一的事件
        RxBus.getInstance().toObservable(EventOne.class)
                .subscribe(new Consumer<EventOne>() {
                    @Override
                    public void accept(EventOne eventOne) throws Exception {
                        mTextView.setText("已接收" + eventOne.getMsg());
                    }
                });

        //订阅消息类型二的事件
        RxBus.getInstance().toObservable(EventTwo.class)
                .subscribe(new Consumer<EventTwo>() {
                    @Override
                    public void accept(EventTwo eventTwo) throws Exception {
                        mTextView.setText("已接收" + eventTwo.getMsg());
                    }
                });
    }

  在第二个界面中分别点击发送消息后,第一个界面中的效果。
事件一

事件二
  可以看到第一个界面分别对两个事件作出了反应。我们通过第二个 Activity
对第一个 Activity 中的数据进行了修改。RxBus 和 EventBus 的用法差不多,也就是创建要传递的事件类,在一个地方发送消息,在另一个地方接收处理消息。如果要传递不同的事件,就创建不同的事件类,用起来还是很方便的。

最后

  RxBus 和 EventBus 为我们提供了事件总线的方式,将一些操作进行了解耦,方便了我们的操作,适当的使用可以提高我们的编程效率,让我们可以把重点放在业务上而不是它的实现上,说白了就是程序员喜欢偷懒,哈哈。
  关于 RxBus 和 EventBus 两者之间的选择,那就仁者见仁智者见智了,如果项目里有用到 RxJava 就可以考虑用一下 RxBus, 如果要用 EventBus 也是可以的,我看了一下 EventBus 的包,其实也不大。

以上就是对 RxBus 的介绍。

猜你喜欢

转载自blog.csdn.net/weixin_42247440/article/details/81698299