看了许多讲解RxJava的文章,有些文章讲解的内容是基于第一个版本的,有些文章的讲解是通过比较常用的一些API和基础的概念进行讲解的。
但是每次看到RxJava的类中的几十个方法的时候,总是感觉心里没底。所以,我打算自己去专门写篇文章来从API的角度系统地梳理一下RxJava的各种方法和用法。
1、RxJava 基本
1.1 RxJava 简介
RxJava是一个在Java VM上使用可观测的序列来组成异步的、基于事件的程序的库。
虽然,在Android中,我们可以使用AsyncTask来完成异步任务操作,但是当任务的梳理比较多的时候,我们要为每个任务定义一个AsyncTask就变得非常繁琐。
RxJava能帮助我们在实现异步执行的前提下保持代码的清晰。
它的原理就是创建一个Observable
来完成异步任务,组合使用各种不同的链式操作,来实现各种复杂的操作,最终将任务的执行结果发射给Observer
进行处理。
当然,RxJava不仅适用于Android,也适用于服务端等各种场景。
我们总结以下RxJava的用途:
- 简化异步程序的流程;
- 使用近似于Java8的流的操作进行编程:因为想要在Android中使用Java8的流编程有诸多的限制,所以我们可以使用RxJava来实现这个目的。
在使用RxJava之前,我们需要先在自己的项目中添加如下的依赖:
compile 'io.reactivex.rxjava2:rxjava:2.2.0'
compile 'io.reactivex.rxjava2:rxandroid:2.0.2'
这里我们使用的是RxJava2,它与RxJava的第一个版本有些许不同。在本文中,我们所有的关于RxJava的示例都将基于RxJava2.
注:如果想了解关于Java8的流编程的内容的内容,可以参考我之前写过的文章五分钟学习Java8的流编程。
1.2 概要
下面是RxJava的一个基本的用例,这里我们定义了一个Observable
,然后在它内部使用emitter
发射了一些数据和信息(其实就相当于调用了被观察对象内部的方法,通知所有的观察者)。
然后,我们用Consumer
接口的实例作为subscribe()
方法的参数来观察发射的结果。(这里的接口的方法都已经被使用Lambda简化过,应该学着适应它。)
Observable<Integer> observable = Observable.create(emitter -> {
emitter.onNext(1);
emitter.onNext(2);
emitter.onNext(3);
});
observable.subscribe(System.out::println);
这样,我们就完成了一个基本的RxJava的示例。从上面的例子中,你或许没法看出Observable
中隐藏的流的概念,看下面的例子:
Observable.range(0, 10).map(String::valueOf).forEach(System.out::println);
这里我们先用Observable.range()
方法产生一个序列,然后用map
方法将该整数序列映射成一个字符序列,最后将得到的序列输出来。从上面看出,这种操作和Java8里面的Stream编程很像。但是两者之间是有区别的:
- 所谓的“推”和“拉”的区别:Stream中是通过从流中读取数据来实现链式操作,而RxJava除了Stream中的功能之外,还可以通过“发射”数据,来实现通知的功能,即RxJava在Stream之上又多了一个观察者的功能。
- Java8中的Stream可以通过
parall()
来实现并行,即基于分治算法将任务分解并计算得到结果之后将结果合并起来;而RxJava只能通过subscribeOn()
方法将所有的操作切换到某个线程中去。 - Stream只能被消费一次,但是
Observable
可以被多次进行订阅;
RxJava除了为我们提供了Observable
之外,在新的RxJava中还提供了适用于其他场景的基础类,它们之间的功能和主要区别如下:
Flowable
: 多个流,响应式流和背压Observable
: 多个流,无背压Single
: 只有一个元素或者错误的流Completable
: 没有任何元素,只有一个完成和错误信号的流Maybe
: 没有任何元素或者只有一个元素或者只有一个错误的流
除了上面的几个基础类之外,还有一个Disposable
。当我们监听某个流的时候,就能获取到一个Disposable
对象。它提供了两个方法,一个是isDisposed
,可以被用来判断是否停止了观察指定的流;另一个是dispose
方法,用来放弃观察指定的流,我们可以使用它在任意的时刻停止观察操作。
1.3 总结
上面我们介绍了了关于RxJava的基本的概念和使用方式,在下面的文章中我们会按照以上定义的顺序从API的角度来讲解以下RxJava各个模块的使用方法。
2、RxJava 的使用
2.1 Observable
从上面的文章中我们可以得知,Observable
和后面3种操作功能近似,区别在于Flowable
加入了背压的概念,Observable
的大部分方法也适用于其他3个操作和Flowable
。
因此,我们这里先从Observable
开始梳理,然后我们再专门对Flowable
和背压的进行介绍。
Observable
为我们提供了一些静态的构造方法来创建一个Observable
对象,还有许多链式的方法来完成各种复杂的功能。
这里我们按照功能将它的这些方法分成各个类别并依次进行相关的说明。
2.1.1 创建操作
1.interval & intervalRange
下面的操作可以每个3秒的时间发送一个整数,整数从0开始:
Observable.interval(3, TimeUnit.SECONDS).subscribe(System.out::println);
如果想要设置从指定的数字开始也是可以的,实际上interval
提供了许多重载方法供我们是使用。下面我们连同与之功能相近的intervalRange
方法也一同给出:
public static Observable<Long> interval(long initialDelay, long period, TimeUnit unit, Scheduler scheduler)
public static Observable<Long> interval(long period, TimeUnit unit, Scheduler scheduler)
public static Observable<Long> intervalRange(long start, long count, long initialDelay, long period, TimeUnit unit, Scheduler scheduler)
这里的initialDelay
参数用来指示开始发射第一个整数的之前要停顿的时间,时间的单位与peroid
一样,都是通过unit
参数来指定的;period
参数用来表示每个发射之间停顿多少时间;unit
表示时间的单位,是TimeUnit
类型的;scheduler
参数指定数据发射和等待时所在的线程。
intervalRange
方法可以用来将发射的整数序列限制在一个范围之内,这里的start
用来表示发射的数据的起始值,count
表示总共要发射几个数字,其他参数与上面的interval
方法一致。
2.range & rangeLong
下面的操作可以产生一个从5开始的连续10个整数构成的序列:
Observable.range(5, 10).subscribe(i -> System.out.println("1: " + i));
该方法需要传入两个参数,与之有相同功能的方法还有rangeLong
:
public static Observable<Integer> range(final int start, final int count)
public static Observable<Long> rangeLong(long start, long count)
这里的两个参数start
用来指定用于生成的序列的开始值,count
用来指示要生成的序列总共包含多少个数字,上面的两个方法的主要区别在于一个是用来生成int型整数的,一个是用来生成long型整数的。
3.create
create
方法用于从头开始创建一个Observable
,像下面显示的那样,你需要使用create
方法并传一个发射器作为参数,在该发射器内部调用onNext
、onComplete
和onError
方法就可以将数据发送给监听者。
Observable.create((ObservableOnSubscribe<Integer>) observableEmitter -> {
observableEmitter.onNext(1);
observableEmitter.onNext(2);
observableEmitter.onComplete();
}).subscribe(System.out::println);
4.defer
defer
直到有观察者订阅时才创建Observable,并且为每个观察者创建一个新的Observable。defer
操作符会一直等待直到有观察者订阅它,然后它使用Observable工厂方法生成一个Observable。比如下面的代码两个订阅输出的结果是不一致的:
Observable<Long> observable = Observable.defer((Callable<ObservableSource<Long>>) () -> Observable.just(System.currentTimeMillis()));
observable.subscribe(System.out::print);
System.out.println();
observable.subscribe(System.out::print);
下面是该方法的定义,它接受一个Callable对象,可以在该对象中返回一个Observable的实例:
public static <T> Observable<T> defer(Callable<? extends ObservableSource<? extends T>> supplier)
5.empty & never & error
public static <T> Observable<T> empty()
:创建一个不发射任何数据但是正常终止的Observable;public static <T> Observable<T> never()
:创建一个不发射数据也不终止的Observable;public static <T> Observable<T> error(Throwable exception)
:创建一个不发射数据以一个错误终止的Observable,它有几个重载版本,这里给出其中的一个。
测试代码:
Observable.empty().subscribe(i->System.out.print("next"),i->System.out.print("error"),()->System.out.print("complete"));
Observable.never().subscribe(i->System.out.print("next"),i->System.out.print("error"),()->System.out.print("complete"));
Observable.error(new Exception()).subscribe(i->System.out.print("next"),i->System.out.print("error"),()->System.out.print("complete"));
输出结果:completeerror
6.from 系列
from
系列的方法用来从指定的数据源中获取一个Observable:
public static <T> Observable<T> fromArray(T... items)
:从数组中获取;public static <T> Observable<T> fromCallable(Callable<? extends T> supplier)
:从Callable中获取;public static <T> Observable<T> fromFuture(Future<? extends T> future)
:从Future中获取,有多个重载版本,可以用来指定线程和超时等信息;public static <T> Observable<T> fromIterable(Iterable<? extends T> source)
:从Iterable中获取;public static <T> Observable<T> fromPublisher(Publisher<? extends T> publisher)
:从Publisher中获取。
7.just 系列
just系列的方法的一个参数的版本为下面的形式:public static <T> Observable<T> just(T item)
,它还有许多个重载的版本,区别在于接受的参数的个数不同,最少1个,最多10个。
8.repeat
该方法用来表示指定的序列要发射多少次,下面的方法会将该序列无限次进行发送:
Observable.range(5, 10).repeat().subscribe(i -> System.out.println(i));
repeat
方法有以下几个相似方法:
public final Observable<T> repeat()
public final Obs