RxBus学习总结与分享

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。看一下运行效果:

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"
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,233评论 6 495
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,357评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,831评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,313评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,417评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,470评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,482评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,265评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,708评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,997评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,176评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,827评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,503评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,150评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,391评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,034评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,063评论 2 352

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,953评论 25 707
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,644评论 18 139
  • 前言我从去年开始使用 RxJava ,到现在一年多了。今年加入了 Flipboard 后,看到 Flipboard...
    占导zqq阅读 9,160评论 6 151
  • 从7月4日决定开始“100天33本”的读书计划到今天,正好十天。从一开始的信心满满,斗志昂扬,到今天,莫名焦虑。我...
    念希爱读书阅读 150评论 0 0
  • 故事梗概是一个中国女孩May爱上了一个犹太难民彼得,想尽一切办法要帮彼得摆脱难民身份,逃离上海去美国,之后...
    eagle0736阅读 464评论 2 7