RxJava2中有两个可以切换线程的操作符,subscribeOn和observeOn。它们有什么区别,如果分别使用多次,会是什么结果。
先说结论:
observeOn() 关注的是在它之后的操作,调用多次则切换多次线程。
subscribeOn() 只有最开始的一次起作用,如果调用多次,只是创建了线程,它去通知它的上游的动作是在这个线程里,但最后onXxx()的动作还是在第一次调用的线程里。
// ObservableRange
Observable.range(1, 10)
// ObservableMap
.map(intValue -> String.valueOf(intValue))
// ObservableSubscribeOn
.subscribeOn(Schedulers.io())
// ObservableObserveOn
.observeOn(AndroidSchedulers.mainThread())
.subscribe(System.out::println);
这是一段简单的io线程创建事件流,主线程消费处理的代码。他们之间是怎么做到线程切换的,这是今天要找到的答案。我在每一行操作符上注释了每个操作符对应生成的Observable,所以最后调用subscribe的是一个ObservableObserveOn对象,他们的subscribe方法都在父类Observable中。
@CheckReturnValue
@SchedulerSupport(SchedulerSupport.NONE)
public final Disposable subscribe(Consumer<? super T> onNext) {
return subscribe(onNext, Functions.ON_ERROR_MISSING, Functions.EMPTY_ACTION, Functions.emptyConsumer());
}
@CheckReturnValue
@SchedulerSupport(SchedulerSupport.NONE)
public final Disposable subscribe(Consumer<? super T> onNext, Consumer<? super Throwable> onError,
Action onComplete, Consumer<? super Disposable> onSubscribe) {
// 省略非空判断
LambdaObserver<T> ls = new LambdaObserver<T>(onNext, onError, onComplete, onSubscribe);
subscribe(ls);
return ls;
}
可以看到,最后会创建一个LambdaObserver,继续调用subscribe
@SchedulerSupport(SchedulerSupport.NONE)
@Override
public final void subscribe(Observer<? super T> observer) {
ObjectHelper.requireNonNull(observer, "observer is null");
try {
observer = RxJavaPlugins.onSubscribe(this, observer);
ObjectHelper.requireNonNull(observer, "The RxJavaPlugins.onSubscribe hook returned a null Observer. Please change the handler provided to RxJavaPlugins.setOnObservableSubscribe for invalid null returns. Further reading: https://github.com/ReactiveX/RxJava/wiki/Plugins");
subscribeActual(observer);
} catch (NullPointerException e) { // NOPMD
throw e;
} catch (Throwable e) {
// 省略异常处理
}
}
关键的地方来了,这里调用了抽象方法subscribeActual,ObservableObserveOn的subscribeActual实现如下:
@Override
protected void subscribeActual(Observer<? super T> observer) {
if (scheduler instanceof TrampolineScheduler) {
source.subscribe(observer);
} else {
Scheduler.Worker w = scheduler.createWorker();
source.subscribe(new ObserveOnObserver<T>(observer, w, delayError, bufferSize));
}
}
这里会判断scheduler的类型,这个成员变量在构造ObservableObserveOn的时候传入,传入的是AndroidSchedulers.mainThread(),是一个HandlerScheduler对象,所以subscribeActual中会进入else继续执行。调用scheduler的抽象方法createWorker创建Scheduler.Worker对象。HandlerScheduler的实现很简单,只是创建HandlerWorker对象:
@Override
public Worker createWorker() {
return new HandlerWorker(handler, async);
}
其中handler就是android中线程调用中的Handler,它使用new Handler(Looper.getMainLooper())中创建,async是false。可见RxAndroid中的切换到main线程使用的还是Handler,流水的开源库,铁打的Handler。最后调用上游的subscribe,传入一个新创建的ObserveOnObserver。此例中上游是一个ObservableSubscribeOn对象,接着调用它的subscribeActual。
@Override
public void subscribeActual(final Observer<? super T> observer) {
final SubscribeOnObserver<T> parent = new SubscribeOnObserver<T>(observer);
observer.onSubscribe(parent);
parent.setDisposable(scheduler.scheduleDirect(new SubscribeTask(parent)));
}
同样创建一个Observer,从ObservableObserveOn中传进来的ObserveOnObserver是它的下游,scheduler是一个IoScheduler对象,会调用它的下面这个方法:
@NonNull
public Disposable scheduleDirect(@NonNull Runnable run, long delay, @NonNull TimeUnit unit) {
final Worker w = createWorker();
final Runnable decoratedRun = RxJavaPlugins.onSchedule(run);
DisposeTask task = new DisposeTask(decoratedRun, w);
w.schedule(task, delay, unit);
return task;
}
IoScheduler对应的Worker实现是EventLoopWorker,它会立即提交执行SubscribeTask,它只是再次调用了上游的subscribe
final class SubscribeTask implements Runnable {
private final SubscribeOnObserver<T> parent;
SubscribeTask(SubscribeOnObserver<T> parent) {
this.parent = parent;
}
@Override
public void run() {
source.subscribe(parent);
}
}
同理ObservableMap也会调用它的上游并且传入自己的Observer,如此往上一直调用,直到最上游,本例中是ObservableRange,看下它的subscribeActual
@Override
protected void subscribeActual(Observer<? super Integer> o) {
RangeDisposable parent = new RangeDisposable(o, start, end);
o.onSubscribe(parent);
parent.run();
}
创建一个RangeDisposable对象,传入的Observer作为它的下游,调用它的run方法
void run() {
if (fused) {
return;
}
Observer<? super Integer> actual = this.downstream;
long e = end;
for (long i = index; i != e && get() == 0; i++) {
actual.onNext((int)i);
}
if (get() == 0) {
lazySet(1);
actual.onComplete();
}
}
在这里会再去调用下游的onNext,下游是ObservableMap里的MapObserver,它在自己的onNext中又去调用它的下游的onNext,
这里是SubscribeOnObserver,要看一下:
@Override
public void onNext(T t) {
downstream.onNext(t);
}
它也只是简单调用下游的onNext()而已,所以如果调用了多次这个方法,相当于下面这段代码:
new Thread(new Runnable() {
@Override
public void run() {
new Thread(new Runnable() {
@Override
public void run() {
// onNext();
// onComplete/onError
}
}).start();
}
}).start();
从下游到上游,从外层到内层,每调用一次就创建一个线程,但是只有最里层的线程也就是最上游的subscribeOn调用起作用,因为onNext,onComplete/onError是在这里调用的。接着在本例中的最后一个下游ObservableObserveOn,对应的Observer是ObserveOnObserver:
@Override
public void onNext(T t) {
if (done) {
return;
}
if (sourceMode != QueueDisposable.ASYNC) {
queue.offer(t);
}
schedule();
}
它之所以可以每调用一次就切换一次线程的原因是,它会在onNext,onComplete/onError中调用schedule
void schedule() {
if (getAndIncrement() == 0) {
worker.schedule(this);
}
}
它会在这里执行线程切换的动作,所以可以每次调用都起作用。
@Override
public Disposable schedule(Runnable run, long delay, TimeUnit unit) {
if (disposed) {
return Disposables.disposed();
}
ScheduledRunnable scheduled = new ScheduledRunnable(handler, run);
Message message = Message.obtain(handler, scheduled);
message.obj = this; // Used as token for batch disposal of this worker's runnables.
handler.sendMessageDelayed(message, unit.toMillis(delay));
return scheduled;
}
通过handler发送一个延时消息,只不过delay为0,这样就执行在Handler所在的线程了,其他线程的切换也类似。