【译】使用RxJava代替EventBus类库

作者: 小鄧子 | 来源:发表于2016-02-17 12:55 被阅读6154次

    如今的Android社区,人人都在讨论RxJava以及为什么我们应该在项目中使用RxJava。当我们开始在Android项目中使用RxJava的时候,就已经意识到了,我们的代码库可以不再需要Otto了(或其他事件总线类库)。

    使用MVP构建代码库

    当我们在开发一款叫做Radyoland的无线流媒体应用的时候,我们决定使用MVP模式来设计我们的代码库和项目架构等。于是我们把它分为几个层(domain, model, app等等)。

    在model层中,存在一些类和接口用来处理RESTful。而domain层中,我们试图实现应用的业务逻辑,因此创建了一些usecase类。

    为什么需要事件总线类库?

    如果你的Android程序中有超过一个逻辑层,就意味着你有可能在层与层之间进行数据的传递。在我们的例子中,我们认为,为DataBusUIBus创建一个BusUtil就能够轻松实现层与层之间的数据传递(model, domain, presentation)。

    你可以“订阅”或者“取消订阅”从bus中所发送出的具体事件。这个方法的工作原理看起来就是这样。

    UsecaseController,**PresenterImp **类之间,我们把REST实现类中得到的结果作为事件发送,然后订阅此事件。

    @Override public void getRadioList() {
        Call<RadioWrapper> radioWrapperCall = restInterface.getRadioList();
        radioWrapperCall.enqueue(new Callback<RadioWrapper>() {
          @Override public void onResponse(Response<RadioWrapper> response, Retrofit retrofit) {
            dataBus.post(response.body());
          }
    
          @Override public void onFailure(Throwable t) {
            Timber.e(t.getMessage());
          }
        });
      }
    

    当我们通过回调函数进行异步请求的时候,使用bus发送请求成功后的结果,然后订阅这个结果事件。

    @Subscribe @Override public void onRadioListLoaded(RadioWrapper radioWrapper) {
        new SaveDatabase(radioWrapper, databaseSource).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
        uiBus.post(radioWrapper);
      }
    

    然后再次发送这个事件至更新UIActivity 或者Fragment 应该在onResume()方法中订阅需要的事件,相反地,在onPause()中对不需要的事件解除订阅。

    @Subscribe @Override public void onRadioListLoaded(RadioWrapper radioWrapper) {
        radioListView.onListLoaded(radioWrapper);
        radioListView.dismissLoading();
      }
    

    虽然,这种方案很有效。但是,作为优秀的Android工程师,应该尝试去发现更好的实现思路。因此,我们找到了一种摆脱所有回调函数和订阅方法的思路。那就是在Android应用的代码库中引入并使用RxJavaRxAndroid

    如何使用RxJava

    首先,我们需要更改所有REST接口的返回类型。

    不使用RxJava:

    @GET("")
    Call<RadioWrapper> getRadioList();
    

    使用RxJava:

    @GET("")
    Observable<RadioWrapper> getRadioList();
    

    REST实现类中,我们持有很多API调用方法。在这里,我只举出其中一例。开始使用RxJava之后,我们需要修改所有方法的实现方式。返回类型将变为Observable,当做完必要的修改之后,方法看起来如下:

    @RxLogObservable @Override public Observable<RadioWrapper> getRadioList() {
        return restInterface.getRadioList();
      }
    

    我们已经完成了REST实现类的修改。接下来,我们要做的是修改usecase实现类和其中的方法。

    @Override public Observable<RadioWrapper> getRadioList() {
    
        /**
         * Get radiolist observable from Cache
         */
        Observable<RadioWrapper> radioListDB = databaseSource.getRadioList().filter(new Func1<RadioWrapper, Boolean>() {
          @Override public Boolean call(RadioWrapper radioWrapper) {
            return radioWrapper.radioList.size() > 0;
          }
        }).subscribeOn(Schedulers.computation());
    
        /**
         * Load radiolist from api layer and save it to DB.
         */
        Observable<RadioWrapper> radioListApi = apiSource.getRadioList().doOnNext(new Action1<RadioWrapper>() {
          @Override public void call(final RadioWrapper radioWrapper) {
            Observable.create(new Observable.OnSubscribe<Object>() {
              @Override public void call(Subscriber<? super Object> subscriber) {
                databaseSource.save(radioWrapper);
                subscriber.onCompleted();
              }
            }).subscribeOn(Schedulers.computation()).subscribe();
          }
        }).subscribeOn(Schedulers.io());
        
        /**
         * concat db and api observables
         */
        return Observable.concat(radioListDB, radioListApi).observeOn(AndroidSchedulers.mainThread());
      }
    

    现在,getRadioList()方法将返回Observable数据流传至UI。就如你所见到的一样,我们不再使用Event bus来发送事件了。可以通过对数据流的过滤,合并,缓存或者其他操作,来达到我们的目的了。

    我们学到了什么

    尽管RxJava用起来不是那么容易,但是当用RxJava替换掉Otto后,我们从代码库中成功移除了很多回调代码块。依我看来,RxJava最棒的地方就是能够对任何REST API进行异步请求。

    如果你有更好的方式能够实现它,请尽情在下方留言,或者把你认为优秀的示例分享出来。

    相关文章

      网友评论

      • 捡淑:高深
        捡淑:@_悟空爹爹 像吗?哪里像屌?
        cd7353f2bcb8:头像屌
      • 修得养得梦得过得:还是没动RxJava是什么
        小鄧子:@修得养得梦得过得 一个类库
      • 全世界_gl:哥哥,我真的想知道,怎么优雅的使用简书的代码块,有点难用啊,直接复制过来的代码不换行怎么破
        HuDP:@全世界_gl http://www.jianshu.com/p/q81RER
      • 键盘男:把rest API放model层不妥,网络请求经常跟UI交互。
        小鄧子:@苦逼键盘男kkmike999 其实,如果细读原文的话,我们是能够从中看出一些端倪的,不过在这之前我还是要说一下,就如我们所了解到的那样,MVP虽然将视图与逻辑分离出来,而且按照KISS原则来讲V层就变得很单纯,很简单,这也就意味着P层要承载更多的逻辑,一不小心P层就会异常臃肿,而且V->P->M基于是依赖关系,组件之间的数据通信通过Callback来完成。那么从第一张图中可以清晰的了解到,原作者为了减少Callback的出现使用了事件总线类库(Otto)来进行数据的传递,而且我个人认为类似Rest、DB甚至SP这类可序列化的Repository,放在M中简直不能更合适了,另外值得一提的是,model并不是特指某些类或者实体对象,它理应是个概念的抽象表现。最后,我想说的是,如果想尝试着减少P层的压力,使用manager或许是个不错的选择 :)
        键盘男:@小鄧子 按照原文意思,domain是放业务相关代码,那restful就独立出来,与MODEL同等级,domain调用model与Restful。作者的MVP有点奇怪,那个M应该是Manager....
        小鄧子:@苦逼键盘男kkmike999 那么放在哪里合适呢?
      • 皮球二二:请问有完整的源码链接看吗?
      • stormzhang:文章不错!
      • lovexiaov:伟哥威武,赞👍
      • __Berial___:rest的实现类指的是model层中的代码么

      本文标题:【译】使用RxJava代替EventBus类库

      本文链接:https://www.haomeiwen.com/subject/fhrpkttx.html