放弃RxBus,拥抱RxJava(一):为何避免使用EventBus/RxBus | 掘金技术征文

这一系列文章原本我发表在简书。最近开始转移到掘金。之后也会在掘金发表(慢慢抛弃简书了应该,掘金的技术环境确实比简书好些)。javascript

EventBus和Otto在以前做为Android组件间通讯工具,简单方便十分受欢迎,可是也很是容易Abuse。大概有以下几个缺点:java

  • 因为是Event,在发布Event的时候就要作好准备可能并无人接受这个Event, Subscribe的时候也要作好准备可能永远不会收到Event。Event不管顺序仍是时间上都某种程度上不太可控。若是你将数据寄托在Event上而后就直接在Android其余生命周期方法中直接使用这个数据或成员变量。那么颇有可能你会获得NPE。
  • EventBus看似将你的程序解耦,可是又有些过了。咱们经常使用EventBus传数据,这已是Dependency级别的数据而不是一个能够被解耦出来的模块。这样就形成了过多EventBus的代码会形成代码结构混乱,难以测试和追踪,违背了解耦的初衷。这时若是有意或无心的形成了Nested Event。那状况会更糟。

因为EventBus的种种缺点,以及后面RxJava的出现。不少人都开始使用RxJava来取代EventBus。甚至Otto的官方介绍里都写到:android

Deprecated!

This project is deprecated in favor of RxJava and
RxAndroid. These projects permit the same event-driven
programming model as Otto, but they’re more capable and offer better control of threading.git

If you’re looking for guidance on migrating from Otto to Rx, this post
is a good start.github

连接是一个教你怎么使用RxJava来本身手动写一个RxBus来代替EventBus的文章。虽然看起来是在用RxJava。可是实际上却仍然在用EventBus。甚至这个封装其实也并无GreenRobot或者Otto来的好。
咱们看看Jake Wharton对RxBus的评价:
编程


我想"RxBus"惟一的好处就是他是一个Rx的入门毒品。不然的话,你要么就不是在用Rx,要么你须要更加惯用的Rx资源 (渣翻译见谅)

再来一个GitHub的:
安全

subscribeActual部分咱们先不考虑。然而Jake指出最好不要使用Relay来“从新发明”Event Bus.app

这里看图说话:
Jake Wharton在GOTO 2016 上的讲座中提到,咱们正常的Android编程是这样的:
ide


咱们像一个中间人同样。
而使用RxJava。 咱们的结构,更像这样

咱们使用RxJava来直接把组件相连,对所接受到的数据做出反应,所谓的 "Reactive"。
而使用Eventbus? Jake 没说, 我本身画一个:


咱们做为一个中间人,传递消息。EventBus做为另外一个中间人。帮咱们传递消息。(这也就是所谓的“看似解耦”)

再打个比方,虽然咱们将EventBus翻译成时间总线,可是其实总线就是Bus也就是公交车。而RxJava更像一个专车,Uber或者滴滴。他直接连接你的两个或多个须要通讯的类。传输数据,固然你能够作一个很大的专车,穿梭在全部类之间,也就是所谓的RxBus。因此在这里为何放弃RxBus也就不言而喻了不是?工具

那么,问题来了?

怎样才是正确(正常?)的RxJava使用方式?

其实Jake 也在GitHub的讨论上给出了一个答案:

因此应该是,每当你想发布一个Event在EventBus时,直接暴露一个Observable出来。每当你想接受一个Event时,找到这个Observable而且Subscribe他。

这样作的好处是什么?

  • 目标和地点都很明确。你的Subscriber明确的知道他Subscribe的是谁,并且明确的知道我须要做出什么反应。这也正是RxJava的核心“响应式编程”。
  • 因为使用了Observable,对于异常处理将会很是方便。并且还有功能强大全面的Operator来辅助你。
  • 虽然看起来耦合性有所增长。可是这是必要的,上面也说过,EventBus虽然在代码上看似解耦。其实他们仍是联系在一块儿的。而咱们这样直接暴露Observable给须要的其余类,这完成了1 -> 1/N的连接,而不须要EventBus这个中间人来传递消息/事件,并且保证咱们须要的事件必定会直接到达。

咱们来举个例子

上下两个Fragment,上面的一个EditText,下面的一个TextView。上面的EditText变化的时候下面的TextView也跟着变化。

先把EditText的TextChangedListener封装在Observable里:

stringObservable = Observable.create(e -> editText.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {

            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                e.onNext(s.toString());
            }

            @Override
            public void afterTextChanged(Editable s) {

            }
        }));

/** *** */
    //Expose Observable
    public Observable<String> getEditTextObservable() {
        return stringObservable;
    }复制代码

不习惯本身封装可使用RxBinding :

stringObservable = RxTextView.textChangeEvents(editText)
                                     .map(event -> event.text().toString());复制代码

再从咱们的TextViewFragment中 取到这个封装好的Observable:

@Override
    public void onStart() {
        super.onStart();
        FragmentEditText fragment = (FragmentEditText) getFragmentManager().findFragmentByTag(FragmentEditText.TAG);
        if(fragment != null){
            fragment.getStringObservable().subscribe(s -> textView.setText(s));
        }
    }复制代码

来看看效果:

固然,这里还有个问题

  • 因为咱们将editText封装在Observable里,不管是create()方法仍是使用RxBinding,都会持有这个View的强引用。形成内存泄漏。因此咱们必定要在最后加入dispose()方法来释放。因此我推荐使用RxBinding,他已经帮咱们在dispose()方法里写好了解除Listener的方法。
  • 由于并无使用publish操做符,致使多个Subscriber的时候仍是有些许问题。能够考虑直接加入.share().

总结:

前几天我在Reddit上看到一我的的回复:

I think EventBus on android is popular because people don't know how to share a java object reference between android components like a Fragment and an Activity, or 2 Activities and so on. So basically I think people don't know how 2 Activites can observe the same object for data changes which I think comes from the fact that we still don't know how to architect our apps properly.

我认为 EventBus在Android上火爆的缘由是人们不知道怎么去在Android组件,例如Activity/Fragment之间共享一个Java对象的引用。

这个回复能够说应该是触到了不少人的痛点。不少状况咱们用EventBus仅仅是不知道如何在多个Fragment/Activity之间共享一个对象。EventBus的作法是在Bus里登记全部的接受者。这点在RxJava里相似,Subject/ConnectableObservable 都有相似的功能。但问题是EventBus做为一个全局Bus,各类不一样类型的事件管理会很麻烦(虽然EventBus把这些事给你作好了,RxBus要本身弄)。咱们有了RxJava彻底能够避免不一样事件的管理。相同事件封装成对应Observable,根据需求选择订阅。这样保持了类型安全,提升了性能,逻辑更清晰。

想想,本身使用EventBus是否是也是这个缘由呢?

掘金技术正文

相关文章
相关标签/搜索