记住!:RxJava的操作符都是对被观察者的处理
一、前期基础知识储备
在笔者的前一篇文章《异步操作库RxJava精炼详解第(一)课:RxJava理论讲解和简单实现》中,分析了RxJava重要的基础理论(观察者模式及其四大元素;响应式编程及其事件调度;RxJava线程控制及其异步操作)并使用RxJava简单实现了一次线程切换的例子。下面本节内容将开始RxJava又一个重要的知识点的讲解—RxJava操作符。
在慕课网的RxJava教程中有一句很经典的总结,笔者拿出来和读者一起分享:“其实核心概念就是两个,被观察者、观察者,然后用各种操作符对被观察者的数据流进行处理,处理成观察者需要的类型后,再发射给观察者”。本节内容可以说是围绕这句话进行具体展开讲解的。
(1)以下是RxJava提供的所有类型的操作符列表,有需要的读者可以参考:
Creating创建操作 - Create/Defer/From/Just/Start/Repeat/Range
Transforming变换操作 - Buffer/Window/Map/FlatMap/GroupBy/Scan
Filtering过滤操作 - Debounce/Distinct/Filter/Sample/Skip/Take
Combining结合操作 - And/StartWith/Join/Merge/Switch/Zip
Error Handling 错误处理- Catch/Retry
Utility 辅助操作 -Delay/Do/ObserveOn/SubscribeOn/Subscribe
Conditional 条件和布尔操作- All/Amb/Contains/SkipUntil/TakeUntil
Mathematical 算术和聚合操作 - Average/Concat/Count/Max/Min/Sum/Reduce
Async 异步操作 - Start/ToAsync/StartFuture/FromAction/FromCallable/RunAsync
Connect 连接操作 -Connect/Publish/RefCount/Replay
Convert 转换操作 -ToFuture/ToList/ToIterable/ToMap/toMultiMap
Blocking 阻塞操作 -ForEach/First/Last/MostRecent/Next/Single/Latest
String 字符串操作 -ByLine/Decode/Encode/From/Join/Split/StringConcat
(2)接着在提供RxJava的官方网站:里面列举了所有操作符的具体讲解,建议有需要的读者收藏起来,方便随时查阅
ReactiveX:http://reactivex.io/documentation/operators.html#filtering
二、上代码,具体实现
笔者在这边文章里,不会一一讲解所有的操作符,而是挑选开发中常用常见的操作符进行讲解,其他操作符,感兴趣的读者可以查阅上面的网址。
请所有读者记住一点:所有操作符都是对被观察者的处理。
(1)创建操作符CreatingObservables (创建被观察者)—用于发射数据
Create通过create操作去创建一个被观察者Observable。Create是最基本的创建Observable的操作符。
Observable<String> observable = Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> subscriber) {
//将依次发射3次onNext ,之后发射onComplete(发射完这个将不会再有输出,同时自动取消注册)
subscriber.onNext("Hello第一次发射");
subscriber.onNext("World第二次发射");
subscriber.onNext("Over 第三次发射");
subscriber.onCompleted();
subscriber.onError(new Throwable());
}
})
平时为了简化被观察者的操作,我们建议使用just和from操作符
Just Just操作符将某个对象转化为Observable对象,并且将其发射出去,可以使一个数字、一个字符串、数组、Iterate对象等。
Observable observable = Observable.just("Hello", "World");
// 将会依次调用:
// onNext("Hello");
// onNext("World");
// onCompleted();
String[] words = {"Hello", "World"};
Observable observable = Observable.from(words);
// 将会依次调用:
// onNext("Hello");
// onNext("World");
// onCompleted();
From(数组、列表)类似于Just但是just会将这个对象整个发射出去。比如说一个含有10个数字的数组,使用from就会发射10次,每次发射一个数字,而使用just会发射一次来将整个的数组发射出去。
Defer (延时效果)订阅事件发生之后才发射数据
<-- 1. 第1次对i赋值 ->>
Integer i = 10;
//通过defer 定义被观察者对象 注:此时被观察者对象还没创建
Observable<Integer> observable = Observable.defer(new Callable<ObservableSource<? extends Integer>>() {
@Override
public ObservableSource<? extends Integer> call() throws Exception {
return Observable.just(i);
}
});
<-- 2. 第2次对i赋值 ->>
i = 15;
// 注:此时,才会调用defer()创建被观察者对象(Observable)
observable.subscribe(new Observer<Integer>() {
@Override
public void onNext(Integer value) {
Log.d(TAG, "接收到的整数是"+ value );
}
@Override
public void onError(Throwable e) {
Log.d(TAG, "对Error事件作出响应");
}
@Override
public void onComplete() {
Log.d(TAG, "对Complete事件作出响应");
}
});//本次请求的返回结果是——“15”,而不是起初就定义好的“10”
Interval(定时器效果 每隔指定时间 就发送事件 常见创建轮询程序)
// 参数1 = 第1次延迟时间;
// 参数2 = 间隔时间数字;
// 参数3 = 时间单位;
Observable.interval(3,1,TimeUnit.SECONDS)
// 该例子发送的事件序列特点:延迟3s后发送事件,每隔1秒产生1个数字(从0开始递增1,无限个)
.subscribe(new Observer<Long>() {
@Override
public void onNext(Long value) {
Log.d(TAG, "接收到了事件"+ value );
}
@Override
public void onError(Throwable e) {
Log.d(TAG, "对Error事件作出响应");
}
@Override
public void onComplete() {
Log.d(TAG, "对Complete事件作出响应");
}
});
// 注:interval默认在computation调度器上执行
// 也可自定义指定线程调度器(第3个参数):interval(long,TimeUnit,Scheduler)
Range(数据范围)|Repeat(重复效果)|Start|Timer (指定延迟时间 定时效果)
———————————————————我是重点分隔线————————————————————
(2)变换操作符TransformingObservables(转换Observable)变换可观测序列来创建一个能够更好的满足我们需求的序列。
讲解RxJava变换操作符之前,先引用“最好的RxJava入门文章”中一句话,见下:
《给 Android 开发者的 RxJava 详解》:“终于要到牛逼的地方了,不管你激动不激动,反正我是激动了。RxJava 提供了对事件序列进行变换的支持,这是它的核心功能之一,也是大多数人说『RxJava 真是太好用了』的最大原因。所谓变换,就是将事件序列中的对象或整个序列进行加工处理,转换成不同的事件或事件序列。”
变化操作符也是RxJava2在开发中重点使用的操作符类型—请读者务必掌握!
Map(转换一个对象,比如数据类型的转化)——将被观察者发送的事件转换为任意的类型事件。
map()是RxJava中常见的变化操作符,用于一对一的变换场景。
Observable.just(1,2,3) // 输入类型 Integer
.map(new Func1<Integer, String>() {
@Override
public String apply(Integer integer) throws Exception {
return integer;
}
}).subscribe(new Consumer<String>() {
@Override
public void accept(String s) throws Exception {
Log.d(TAG, s);
}
});
运行结果:map() 将参数中的 Integer 类型对象转换成一个 String类型对象后返回。这里出现了一个叫做 Func1 的类,是 RxJava 的一个接口,用于包装含有一个参数的方法。Func1 包装的是有返回值的方法。FuncX 也有多个,用于不同参数个数的方法,在以后的开发中你还会见到Fun2。
FlatMap(一对多的转换对象,实际开发中最常见的就是token,然后根据token去获取用户列表)|“铺平”——有多个网络请求,后面的网络请求依赖于前面请求的结果—平铺,不会陷入回调、嵌套地狱)
Flat——英文释义:平铺,铺平
在复杂的场景中,我们有一个这样的Observable:它发射一个数据序列,这些数据本身也可以发射Observable。RxJava的flatMap()函数提供一种铺平序列的方式,然后合并这些Observables发射的数据,最后将合并后的结果作为最终的Observable。
假设这样一个场景:我们需要统计每个学生手上的书籍名称。学生是一个对象,即被观察者,书籍也是一个被观察者,在这个场景中一共涉及到了两个被观察者。此时我们就可以使用FlatMap,进行数据平铺后,在发射给观察者。
Student[] students = ...;
Subscriber<Book> subscriber = new Subscriber<Book>() {
@Override
public void onNext(Book book) {
Log.d(tag, book.getName());
}
...
};
Observable.from(students)
.flatMap(new Func1<Student, Observable<Book>>() {
@Override
public Observable<Book> call(Student student) {
return Observable.from(student.getBooks());
}
})
.subscribe(subscriber);
flatMap()也是RxJava中一种常见的变化操作符,用于一对多的场景,flatMap() 的原理是这样的:1. 使用传入的事件对象创建一个 Observable 对象;2. 并不发送这个 Observable, 而是将它激活,于是它开始发送事件;3. 每一个创建出来的 Observable 发送的事件,都被汇入同一个 Observable ,而这个 Observable 负责将这些事件统一交给 Subscriber 的回调方法。
注:使用FlatMap后得到的数据序列被打乱了。
———————————————————以上两个操作符请重点关注———————————————
GroupBy(分组,分类发送到观察者手上,RxJava提供了一个有用的函数GroupBy从列表中按照指定的规则分组元素,比如歌曲按照下载时间/听歌次数/首字母排序)
Buffer(发射定义好数据量的一组数据,RxJava中的buffer()函数将源Observable变换一个新的Observable,这个新的Observable每次发射一组列表值而不是一个一个发射。用的少)
Scan(累加,发射累加起的数据。用的少)
Window(与Buffer类似。用的少)
(3)过滤操作符FilteringObservables(过滤Observable),设立条件,让我们能够从我们接收到的序列中创建我们需要的序列。意味着我们不需要知道可观测序列的源或者为什么发射这么多不同的数据。我们只是想要这些元素的子集来创建一个可以在应用中使用的新序列。这种思想促进了我们编码中的分离性与抽象性。
Debounce(指定时间间隔内没有其他数据发射,则发射该数据,debounce()函数过滤掉由Observable发射的速率过快的数据;如果在一个指定的时间间隔过去了仍旧没有发射一个,那么它将发射最后的那个)
TimeOut(我们可以使用timeout()函数来监听源可观测序列,就是在我们设定的时间间隔内如果没有得到一个值则发射一个错误,触发onError()函数)
Distinct(去掉重复的数据项,一个可观测序列会在出错时重复发射或者被设计成重复发射,而Distinct可以帮我们解决这个问题)
ElementAt(取出指定位置的数据)
IgnoreElements(忽略所有数据,不发射数据给观察者 直接回调onCompleted()/onErro())
Filter(设立条件 过滤数据,取得我们所要的数据)
First(取出第一位数据)|Last(取出最后一位数据)
Sample(指定时间间隔进行数据采样 采样之后再发射一组数据给观察者 该方法会创建一个新的可观测序列)
Skip(跳过前面数据项,取后面的数据)|SkipLast(跳过后面数据,取前面的数据)
Take(取前面数据)|TakeLast(取后面数据)
(4)组合操作符CombiningObservables(组合Observable)组合Observable,合并它们,连接它们,再或者打包它们。
Zip(两两组合不同的数据源,然后发射给观察者)
Merge(按照时间顺序组合不同的数据源,然后发射给观察者)
CombineLatest(两个数据源根据发射时间的先后,时间距离最近的2项数据源组合)
StartWith(在当前数据源之前插入另外的数据)
Join(自定义组合条件)
Switch(将一个发射多个Observables的Observable转换成另一个单独的Observable,后者发射那些Observables最近发射的数据项)
总结:本节内容主要是讲解了RxJava中常见和常用的操作符,并举例实现了最为重要的几个创造和变化类型的操作符。在文章的末尾,笔者还是想引用慕课网的那句经典的总结——“其实核心概念就是两个,被观察者、观察者,然后用各种操作符对被观察者的数据流进行处理,处理成观察者需要的类型后,再发射给观察者”。文章的前部列举了所有的操作符并且提供了ReactiveX的网址,有需要其他操作符的读者可以上网参阅。
下篇笔者RxJava的文章将结合“线程控制Scheduler”和“操作符”来具体讲解RxJava的使用场景