了解本章内容请最好是先了解
RxJava2操作符内部流程理解-概念
repeat操作符就是指的"重复",当上游发送数据结束了之后,在这个操作符内部会再次往上游订阅数据,再次触发subscribeActual 方法。这样就可以再次从头到尾的获得一遍之前的全部数据,根据传入的参数,repeat 可以多次重复。
示例代码
Observable.range(0, 10).repeat(5).subscribe(new Consumer<Integer>() {
@Override
public void accept(Integer integer) throws Exception {
print("s:" + integer);
}
});
按照我们的思路,肯定得进入repeat操作符里面去看看
step1
@CheckReturnValue
@SchedulerSupport(SchedulerSupport.NONE)
public final Observable<T> repeat(long times) {
if (times < 0) {
throw new IllegalArgumentException("times >= 0 required but it was " + times);
}
if (times == 0) {
return empty();
}
return RxJavaPlugins.onAssembly(new ObservableRepeat<T>(this, times));
}
好的,这里进行一系列的参数检查之后,来到了我们的老套路,创建一个 ObservableRepeat,继续
step2
@Override
public void subscribeActual(Observer<? super T> observer) {
SequentialDisposable sd = new SequentialDisposable();
observer.onSubscribe(sd);
RepeatObserver<T> rs = new RepeatObserver<T>(observer, count != Long.MAX_VALUE ? count - 1 : Long.MAX_VALUE, sd, source);
rs.subscribeNext();
}
来到我们熟知的方法 subscribeActual,这里也是创建一个 RepeatObserver,我们注意到下面的这个名字叫 subscribeNext 的方法,它应该也是订阅,但是方法名让我们更加留意了。
step3
void subscribeNext() {
if (getAndIncrement() == 0) {
int missed = 1;
for (;;) {
if (sd.isDisposed()) {
return;
}
source.subscribe(this);
missed = addAndGet(-missed);
if (missed == 0) {
break;
}
}
}
}
这个方法内部使用了父类是原子类的特点控制变量来保证线程安全,大概流程是:当变量为0的时候,变量加1,然后执行订阅上游的操作,订阅完成之后,再次变量减为0.这样空值了订阅这个操作不会出现多线程问题。
这里我们猜想就是repeat的关键所在。
step4
我们查看 RepeatObserver 这个类,我们知道这个类是用来获取上游onNext传下来的数据的,以往分析都会进入onNext 方法里面一探究竟,但是我们发现这里的onNext居然没有做任何事情,直接往下游传递了数据
@Override
public void onNext(T t) {
downstream.onNext(t);
}
使用这个操作的时候我们知道,它是每次等上游发送完毕了之后才开始重复的,所以我想它一定是在onComplete方法里面处理的,果然。
@Override
public void onComplete() {
long r = remaining;
if (r != Long.MAX_VALUE) {
remaining = r - 1;
}
if (r != 0L) {
subscribeNext();
} else {
downstream.onComplete();
}
}
相信来到这里大家就会很明了了,remaining,顾名思义就是剩余量的意思,重复过程中还剩多少次,当剩余次数不为0的时候回调用我们之前看到的 subscribeNext() 再次订阅触发上游的数据事件,最终重复次数达到的时候,触发下游的 onComplet() ,完成。
同理我们可以去查看 repeatUntil(),repeatWhen(),这两个操作符,大同小异,只是传入了一个 BooleanSupplier,或者 Function来做条件判断。
repeatWhen() 有一点复杂是因为,它提供一个可观察者对象,这个对象会在上游事件onComplete的时候触发一下自己的onNext,也就是通知上游事件完成了,然后在apply 里面返回一个可观察者对象,这个对象发送数据的时候会触发重复订阅的操作,由于只是关心发送数据这件事情,而不是发送数据的内容,所以内部并没有用到传入的数据,所以这里写了一个object对象来通用。
Observable.range(0, 10).repeatWhen(new Function<Observable<Object>, ObservableSource<?>>() {
@Override
public ObservableSource<?> apply(Observable<Object> signaller) throws Exception {
// signaller 是内部的,上游结束之后会触发这个signaller
return signaller.flatMap(new Function<Object, ObservableSource<?>>() {
@Override
public ObservableSource<?> apply(Object o) throws Exception {
return Observable.timer(3, TimeUnit.SECONDS);
}
});
}
}).blockingSubscribe(new Consumer<Integer>() {
@Override
public void accept(Integer integer) throws Exception {
print("i:" + integer);
}
});
总结
这个操作很简单,逻辑也很清晰,但是有一点值得思考的是它是依靠再次订阅触发 subscribeActual() 来达到发送数据的效果的,这对just,from,rang,create 这些操作符有效果,因为他们都在 subscribeActual() 方法里面直接触发了数据发送。
但是对PublishSubject 这样特殊的类就没效果了,因为它是靠直接onNext()发送数据的,并不是在我们期待的 subscribeActual() 里面。请看下面代码
PublishSubject<String> subject = PublishSubject.create();
subject.repeat(6).subscribe(new Observer<String>() {
@Override
public void onSubscribe(Disposable d) {
System.out.println();
}
@Override
public void onNext(String s) {
System.out.println(s);
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
System.out.println("onComplete");
}
});
subject.onNext("hello1");
subject.onNext("hello2");
subject.onNext("hello3");
subject.onNext("hello4");
subject.onNext("hello5");
subject.onNext("hello6");
subject.onNext("hello7");
运行结果:
hello1
hello2
hello3
hello4
hello5
hello6
hello7
并不是我们想要的那样。这需要注意。