本文将分析RxJava2中常见的操作符。
RxJava有许多操作符,提供了很多不同的功能,而最终的目的就是将上游的Observable转换成不同的Observable对象实现不同的功能。举几个栗子:
操作符前后的对象都是ObservableSource的子类,并且下游会持有上游的对象,在调用subscribeActual的时候也会执行上游的逻辑。
emmmmm......说起来有点乱,我拿几个常用的操作符来举例说明。
· just
just的作用是将参数依次发射出来,而且有很多的重载方法
除了单参数的之外,别的方法都会调用fromArray,这个放到后面说。
just单参数方法将上游对象转变成ObservableJust对象:
public final class ObservableJust<T> extends Observable<T> implements ScalarCallable<T> {
private final T value;
public ObservableJust(T value) {
this.value = value;
}
protected void subscribeActual(Observer<? super T> s) {
ScalarDisposable sd = new ScalarDisposable(s, this.value);
s.onSubscribe(sd);
sd.run();
}
public T call() {
return this.value;
}
}
ObservableJust的逻辑很清晰,我们只需要关心ScalarDisposable的run()方法即可。
public static final class ScalarDisposable<T> extends AtomicInteger implements QueueDisposable<T>, Runnable {
/*省略部分代码*/
final Observer<? super T> observer;
final T value;
public ScalarDisposable(Observer<? super T> observer, T value) {
this.observer = observer;
this.value = value;
}
public void run() {
if(this.get() == 0 && this.compareAndSet(0, 2)) {
this.observer.onNext(this.value);
if(this.get() == 2) {
this.lazySet(3);
this.observer.onComplete();
}
}
}
}
ScalarDisposable在这里的逻辑也很清晰,就是把上游的onNext事件交给Observer的onNext方法处理。完成了RxJava的调用。
· fromArray
上面说到多个参数的just方法都会调用到fromArray方法,拿两个参数的为例:
public static <T> Observable<T> just(T item1, T item2) {
ObjectHelper.requireNonNull(item1, "The first item is null");
ObjectHelper.requireNonNull(item2, "The second item is null");
return fromArray(new Object[]{item1, item2});
}
更多参数也一样,都会把参数转换成数组传递给fromArray方法。而fromArray会返回ObservableFromArray对象,看看ObservableFromArray就知道具体的实现了:
public final class ObservableFromArray<T> extends Observable<T> {
/*省略部分代码*/
final T[] array;
public ObservableFromArray(T[] array) {
this.array = array;
}
public void subscribeActual(Observer<? super T> s) {
ObservableFromArray.FromArrayDisposable d = new ObservableFromArray.FromArrayDisposable(s, this.array);
s.onSubscribe(d);
if(!d.fusionMode) {
d.run();
}
}
static final class FromArrayDisposable<T> extends BasicQueueDisposable<T> {
final Observer<? super T> actual;
final T[] array;
int index;
boolean fusionMode;
volatile boolean disposed;
FromArrayDisposable(Observer<? super T> actual, T[] array) {
this.actual = actual;
this.array = array;
}
void run() {
Object[] a = this.array;
int n = a.length;
for(int i = 0; i < n && !this.isDisposed(); ++i) {
Object value = a[i];
if(value == null) {
this.actual.onError(new NullPointerException("The " + i + "th element is null"));
return;
}
this.actual.onNext(value);
}
if(!this.isDisposed()) {
this.actual.onComplete();
}
}
}
}
subscribeActual方法会执行到FromArrayDisposable的run方法。然后遍历fromArray中传进来的数组,如果事件流没有被停止,就把数组中的对象交给Observer的onNext方法处理。
· map
map的作用是将上游发射出来的事件转变成另一种事件再传递给下游,说起来有点苍白,还是用代码来演示:
Observable
.just(Integer.valueOf(1))
.map(new Function<Object, Object>() {
@Override
public Object apply(@NonNull Object o) throws Exception {
return String.valueOf(o);
}
})
.subscribe(new Observer<Object>() {
@Override
public void onSubscribe(Disposable disposable) {
}
@Override
public void onNext(Object s) {
Log.d("rxrx", "onNext:" + s);
Log.d("rxrx", "onNext:" + s.getClass());
}
@Override
public void onError(Throwable throwable) {
}
@Override
public void onComplete() {
}
});
04-25 09:55:43.620 24606-24606/com.newhongbin.lalala D/rxrx: onNext:1
04-25 09:55:43.620 24606-24606/com.newhongbin.lalala D/rxrx: onNext:class java.lang.String
结合日志可以看到,上游发送出来的Integer到了下游变成了String,而这个变换的过程就在map中实现。实现原理也比较简单,在Observable中调用apply方法返回转换后的对象,再交给Observer的onNext方法处理。
· flatMap、concatMap、switchMap
flatMap、concatMap、switchMap都跟map一样起到了变换的作用,但是他们变换后的对象都是ObservableSource的实现类,将上游的事件依次包装成ObservableSource的实现类再与Observer进行关联。变换前是1个被观察者,N个事件,变换后就变成N个被观察者。
三者的区别:
flatMap:发射事件无序。
concatMap:事件有序,与上游的顺序一致。
switchMap:如果前面的事件没有发射出去,就丢弃,发射当前最新的事件。
如果上游分别延时发射 "1","2","3","4","5",经过这三种变换后Observer的执行情况分别为:
flatMap:因为无序发射,执行情况不一定。
concatMap:按顺序发射,按顺序执行"1","2","3","4","5"。
switchMap:新的事件到来时,上一个还没有发射,所以发射最新的,最终只执行了"5"。
· buffer
buffer用于控制Observer一次处理的数量,结合示例来看:
Observable
.just(1,2,3,4,5,6,7,8,9,10)
.buffer(3, 3)
.subscribe(new Observer<Object>() {
@Override
public void onSubscribe(Disposable disposable) {
Log.d("rxrx", "onSubscribe:");
}
@Override
public void onNext(Object s) {
Log.d("rxrx", "onNext:" + s);
}
@Override
public void onError(Throwable throwable) {
}
@Override
public void onComplete() {
}
});
04-25 14:17:30.532 32283-32283/com.newhongbin.lalala D/rxrx: onSubscribe:
04-25 14:17:30.532 32283-32283/com.newhongbin.lalala D/rxrx: onNext:[1, 2, 3]
04-25 14:17:30.532 32283-32283/com.newhongbin.lalala D/rxrx: onNext:[4, 5, 6]
04-25 14:17:30.532 32283-32283/com.newhongbin.lalala D/rxrx: onNext:[7, 8, 9]
04-25 14:17:30.532 32283-32283/com.newhongbin.lalala D/rxrx: onNext:[10]
上游依次发射了10个事件,下游的Obsever每次处理buffer指定的事件数量个,不足的也一次处理。第一个参数表示一次处理的事件数量,第二个参数表示下一次处理事件时要在跳过几个事件。当两个参数相同时,Observer会被包装成BufferExactObserver,看看BufferExactObserver的四个方法:
public void onSubscribe(Disposable s) {
if(DisposableHelper.validate(this.s, s)) {
this.s = s;
this.actual.onSubscribe(this);
}
}
public void onNext(T t) {
Collection b = this.buffer;
if(b != null) {
b.add(t);
if(++this.size >= this.count) {
this.actual.onNext(b);
this.size = 0;
this.createBuffer();
}
}
}
public void onError(Throwable t) {
this.buffer = null;
this.actual.onError(t);
}
public void onComplete() {
Collection b = this.buffer;
this.buffer = null;
if(b != null && !b.isEmpty()) {
this.actual.onNext(b);
}
this.actual.onComplete();
}
在事件发送到到onNext的时候,并不会立即交给Observer处理,而是放到一个集合中,当集合的数量达到我们的限定值时会把整个集合交给Observer的onNext处理。最后事件全部发送完毕,调用onComplete,如果这时候集合中还有事件没有处理的,就先把集合交给Observer的onNext处理,再执行Observer的onComplete方法。
buffer有非常多的重载方法,支持多种数量指定的方式,比如:
public final Observable<List<T>> buffer(long timespan, TimeUnit unit) {
return this.buffer(timespan, unit, Schedulers.computation(), 2147483647);
}
这个方法可以指定Observer每次处理单位时间内发射的事件。
· zip
zip的作用是将多个Observable发射出来的事件组合到一起,结合成一个事件序列传给下游。下面用一个简单的例子说明:
Observable<String> stringObservable = Observable.create(new ObservableOnSubscribe<String>() {
@Override
public void subscribe(ObservableEmitter<String> observableEmitter) throws Exception {
//发出3个字符串事件“一”、“二”、“三”
observableEmitter.onNext("一");
observableEmitter.onNext("二");
observableEmitter.onNext("三");
observableEmitter.onComplete();
}
});
Observable<Integer> integerObservable = Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(ObservableEmitter<Integer> observableEmitter) throws Exception {
//发出2个整型事件1、2
observableEmitter.onNext(1);
observableEmitter.onNext(2);
observableEmitter.onComplete();
}
});
Observable.zip(stringObservable, integerObservable, new BiFunction<String, Integer, Object>() {
@Override
public Object apply(@NonNull String s, @NonNull Integer integer) throws Exception {
//多种事件的组合方式
return s + integer;
}
}).subscribe(new Observer<Object>() {
@Override
public void onSubscribe(Disposable disposable) {
Log.d("rxrx", "start");
}
@Override
public void onNext(Object o) {
Log.d("rxrx", o.toString());
}
@Override
public void onError(Throwable throwable) {
}
@Override
public void onComplete() {
Log.d("rxrx", "onComplete");
}
});
05-10 15:41:21.440 31242-31242/com.newhongbin.lalala D/rxrx: start
05-10 15:41:21.440 31242-31242/com.newhongbin.lalala D/rxrx: 一1
05-10 15:41:21.440 31242-31242/com.newhongbin.lalala D/rxrx: 二2
05-10 15:41:21.440 31242-31242/com.newhongbin.lalala D/rxrx: onComplete
这个例子将两个Observable组合到一起,按照apply中的合并规则合并事件,而且通过最后的结果也可以知道,最终的事件数量以较少的Observable的事件数量为准。我本来想辅以源码详细说说zip的原理,但是想想这个代码绕来绕去有点晕,我试试能不能简单的说清楚。
首先上游会传入n个Observable,组装成Observable[n]。zip方法会根据Observable的数量创建n个ZipObserver,与n个Observable一一关联。每个ZipObserver内部维护了一个队列,当上游Observable发射事件的时候,对应的ZipObserver会把事件放入队列,然后执行drain方法。drain的工作就是遍历所有的ZipObserver,如果所有的ZipObserver的队列都有事件,就按照Function#apply中的规则,转换成最终的事件,交给真正的Observer处理。如果存在ZipObserver的队列中没有事件,drain方法结束,等待下一次的drain。当事件较少的Observable完成所有的事件发射,那么整个zip过程准备结束。(drain方法有点绕,具体的实现也比我说的更为复杂一些,有兴趣可以自行查阅代码)
总结