RxBus学习总结与分享

RxBus主要用来处理应用程序间各个组件的通信,或者组件与组建之间的数据传递。(不用再像BroadcastReceiver一样,把数据封装到intent里面再传递出去了)。
首先,为什么叫他RxBus?其实我也不知道,当初我以为RxBus是一个封装好的库,直接拿过来用就好了。事实并非如此,我找了半天没找到现成的库,都是教你如何去通过RxJava来构造一个RxBus,既然这样,那我也就跟着他们做了。其实说到底,RxBus学的是一种思路,而并不是给你一个现成的库,然后直接去调用。
对RxJava还不熟悉的同学请学习我之前发的文章:RXJava学习最友好的系列资料,以下内容针对有RxJava基础的同学。

public enum RxBus {
    INSTANCE;

    private Subject mRxBusObserverable = new SerializedSubject<>(PublishSubject.create());

    public static void send(Object object) {
        if (INSTANCE.mRxBusObserverable.hasObservers()) {
            INSTANCE.mRxBusObserverable.onNext(object);
        }
    }

    public static Observable 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 setOnNext() {
        return new Action1() {

            @Override
            public void call(Object o) {
                doOnNext(o);
            }
        };
    }

    protected abstract void doOnNext(Object o);

    private void initRxBus(final Action1 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 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。看一下运行效果:

rxbus.gif

当在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"
    }
}

你可能感兴趣的:(RxBus学习总结与分享)