RxJava与Retrofit实战总结

一、ReactiveX简单介绍

Rx是一个使用可观察数据流进行异步编程的编程接口,ReactiveX结合了观察者模式、迭代器模式和函数式编程的精华。Rx提供了一系列的操作符,你可以使用它们来过滤(filter)、选择(select)、变换(transform)、结合(combine)和组合(compose)多个Observable,这些操作符让执行和复合变得非常高效。

在ReactiveX中,一个观察者(Observer)订阅一个可观察对象(Observable)。观察者对Observable发射的数据或数据序列作出响应。这种模式可以极大地简化并发操作,因为它创建了一个处于待命状态的观察者哨兵,在未来某个时刻响应Observable的通知,不需要阻塞等待Observable发射数据。

RxJava与Retrofit实战总结_第1张图片

上图取自ReactiveX官方文档,上面一排图标代表被观察对象产生的事件,横向的箭头代表时间线,有6个事件依次发射,经过中间的转换和处理得到了下面的图标,即处理结果,有些事件发射、处理和接收都成功,而有些事件因为各种原因导致失败,这些情况都会在相应的回调方法中呈现。

Subscribe方法用于将观察者连接到Observable,你的观察者需要实现以下方法的一个子集:

  • onNext(T item)

    Observable调用这个方法发射数据,方法的参数就是Observable发射的数据,这个方法可能会被调用多次,取决于你的实现。

  • onError(Exception ex)

    当Observable遇到错误或者无法返回期望的数据时会调用这个方法,这个调用会终止Observable,后续不会再调用onNext和onCompleted,onError方法的参数是抛出的异常。

  • onComplete

    正常终止,如果没有遇到错误,Observable在最后一次调用onNext之后调用此方法。

根据Observable协议的定义,onNext可能会被调用零次或者很多次,最后会有一次onCompleted或onError调用(不会同时),传递数据给onNext通常被称作发射,onCompleted和onError被称作通知。

二、RxJava与RxAndroid的配合使用

RxJava是 ReactiveX 在JVM上的一个实现,ReactiveX使用Observable序列组合异步和基于事件的程序。RxJava提供了5种调度器,分别是:

  • .io()

    这个调度器时用于I/O操作。它基于根据需要,增长或缩减来自适应的线程池。由于它专用于I/O操作,所以并不是RxJava的默认方法;正确的使用它是由开发者决定的。重点需要注意的是线程池是无限制的,大量的I/O调度操作将创建许多个线程并占用内存。

  • .computation()

    这个是计算工作默认的调度器,它与I/O操作无关。它也是许多RxJava方法的默认调度器:buffer(), debounce(), delay() , interval(), sample(), skip()。

  • .immediate()

    这个调度器允许你立即在当前线程执行你指定的工作。它是timeout(),timeInterval(),以及timestamp()方法默认的调度器。

  • .newThread()

    这个调度器为指定任务启动一个新的线程。

  • .trampoline()

    当我们想在当前线程执行一个任务时,并不是立即,我们可以用.trampoline()将它入队。这个调度器将会处理它的队列并且按序运行队列中每一个任务。它是repeat()和retry()方法默认的调度器。

RxAndroid模块包含RxJava的Android特定的绑定代码。它给RxJava添加了一些类,用于帮助在Android应用中编写响应式(reactive)的组件。它提供了一个可以在给定的Android Handler上调度Observable的调度器 Scheduler,特别是在UI主线程上 AndroidSchedulers.mainThread()。

上面提到了几种线程调度器,可以让开发者在不同的线程执行不同的事件,那么如何指定和切换线程呢?RxJava提供了两个方法subscribeOn和observeOn,前者可以指定Observable事件产生和变换处理的线程,后者可以指定订阅者所在的线程,假如事件是一个耗时任务,完全可以通过subscribeOn指定为计算线程或者子线程,然后再通过observeOn切换Android主线程,即可在订阅者回调方法中操作UI视图。

看一个具体的例子吧。

Observable.just("")
  .subscribeOn(Schedulers.newThread())
  .map(s -> {
    for (PerformanceEntity.Components components : performanceEntity.components) {
        PerformanceSubmitEntity.Data submitData = new PerformanceSubmitEntity.Data();
        submitData.componentId = components.id;
        for (PerformanceEntity.Data data : performanceEntity.data) {
            if (data.componentId == components.id) {
                transferData(submitData, data);
                break;
            }
        }
        submitDataList.add(submitData);
    }
    return null;
  })
  .observeOn(AndroidSchedulers.mainThread())
  .subscribe(o -> {
    initPerformanceView();
  });

在渲染视图之前需要处理大量的数据,那么就可以将Observable的线程切换至子线程,等负责的业务逻辑完成后再切换至UI线程,然后在subscribe中完成视图的渲染。这样即可以保证UI线程不会大量复杂的计算,也可以不用Handler、AsycTask等复杂的操作,代码清晰度也相对较高。

三、RxJava与Retrofit的结合

在Android开发中,网络请求往往是最耗时的,也是情况最复杂的,如果直接在UI线程进行网络请求,编译时就会报错,及时编译报错,运行时系统也会报ANR错误,所以网络请求必须在子线程完成。而网络请求结果一般又需要操作UI视图,所以返回结果的回调有必须在主线程,那么上面提到的方法就可以完美解决这个问题。

网络请求的返回结果一般都是json格式,如果返回值为原始的字符串,那么就需要调用放每次都要进行json至JavaBean的转换,有的时候我们只关心返回结果中的一部分数据,那么就还需要在返回结果中再次对数据进行筛选,还有情况是我们只关心满足一定条件的数据,那么这些需求如果用RxJava来实现就变得异常简单。有关Retrofit详细用法,以及如何将返回结果切换成RxJava处理模式,可以阅读Retrofit用法详解这篇文章,下面直接看示例:

 showProgressBar();
 messageService.messageList(msgType, PAGE_INDEX, PAGE_SIZE)
            .compose(new DefaultTransformer<>(getActivity()))
            .map(messageListResponse -> messageListResponse.data)
            .flatMap(messageListEntity -> Observable.from(messageListEntity))
            .filter(messageEntity.id > 10)
            .subscribe(new Subscriber() {
                @Override
                public void onCompleted() {
                    dismissProgressBar();
                    refreshLayout.setRefreshing(false);
                }
                @Override
                public void onError(Throwable e) {
                    dismissProgressBar();
                    refreshLayout.setRefreshing(false);
                }
                @Override
                public void onNext(MessageEntity messageEntity) {
                    updateView(messageEntity);
                }
            });
  • DefaultTransformer主要实现线程的切换以及错误消息的统一处理,一般来说服务端接口返回的数据格式都比较固定,会有code、message、data,其中code只是正确或者错误类型,message返回正确或者错误日志,data则是业务数据的存放地,那么就可以在DefaultTransformer中统一判断code值,如果是请求出错,那么直接将异常抛给onError回调方法。
  • map中实现的功能就是上文提到的调用方只关心data中的数据,而不关心code和message,那么就可以通过map方法直接将data中的数据传递给订阅者。
  • 如果我们想将返回值List逐条处理,一般的做法就是直接for循环,这里用到了flatMap,就是将messageListEntity通过Observable的from方法重新拆分成更细粒度的MessageEntity,而订阅者得到也就是MessageEntity。
  • filter方法就是通过布尔表达式筛选出符合条件的数据,上述例子中就是将id值大于10的MessageEntity筛选出来。

有关Observable的compose、map、from、flatMap、filter等方法可以参考ReactiveX官方教程,中文环境下可以参考给Android开发者的RxJava详解

欢迎大家关注我的微信公众号蓝田大营,下面是微信公众号二维码:

你可能感兴趣的:(Android)