整体流程
以下面的调用方式为例:
Observable.create(new ObservableOnSubscribe<String>() {
@Override
public void subscribe(ObservableEmitter<String> emitter) throws Exception {
emitter.onNext("hello");
emitter.onNext("world");
emitter.onComplete();
}
}).map(new Function<String, String>() {
@Override
public String apply(String s) throws Exception {
return s + ": after map";
}
}).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<String>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(String s) {
Log.d("MainActivity", "这里是onCreate方法:"+s);
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
});
在上面的调用链中,Observable以及其subscribeActual方法所处理的Observer对象变化流程为:
new ObservableOnSubscribe{ subscribe } -> (ObservableCreate, CreateEmitter) <-> (ObservableMap, MapObserver) <-> (ObsersvableSubscribeOn, SubscribeOnObserver) <-> (ObservableObserveOn, ObserveOnObserver) <- new Observer{ onNext }
从左往右看:前面的Observable为后面的ObservableXX的source属性;从右往左看:前面的Observer为后面的XXObserver的actual属性。
上面是以订阅流程中相关对象的变化来看的,他们间的关系并不是处理与被处理的关系,ObservableXX与XXObserver将按照处理关系绑定的话是如下这样:
new ObservableOnSubscribe{ subscribe }.subscribe(CreateEmitter) <- ObservableCreate.subscribe(MapObserver) <- ObservableMap.subscribe(SubscribeOnObserver) <- ObservableSubscribeOn.subscribe(ObserveOnObserver) <- ObservableObserveOn.subscribe(new Observer{ onNext })
以上就是函数传参 -- 真正订阅关系上各个对象的对应关系。
Observable订阅流程
Observable的订阅流程决定着最初的ObservableOnSubscribe中我们初始化的subscribe方法的调用,因此,对Observable来说,要关注其subscribe方法执行逻辑:
// ObservableCreate.java
@Override
protected void subscribeActual(Observer<? super T> observer) {
CreateEmitter<T> parent = new CreateEmitter<T>(observer);
observer.onSubscribe(parent);
try {
// 直接调用
source.subscribe(parent);
} catch (Throwable ex) {
Exceptions.throwIfFatal(ex);
parent.onError(ex);
}
}
// ObservableMap.java
@Override
public void subscribeActual(Observer<? super U> t) {
// 直接调用
source.subscribe(new MapObserver<T, U>(t, function));
}
// ObservableSubscribeOn.java
@Override
public void subscribeActual(final Observer<? super T> s) {
final SubscribeOnObserver<T> parent = new SubscribeOnObserver<T>(s);
s.onSubscribe(parent);
// scheduler.scheduleDirect()进行切线程,并且只是将source.subscribe(parent)这一过程封装到了Runnable中
parent.setDisposable(scheduler.scheduleDirect(new SubscribeTask(parent)));
}
// ObservableObserveOn.java
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));
}
}
接上文,Observable的subscribeActual方法我们只需要关注source.subscribe()的调用即可,而会影响这一步骤调用的只有ObservableSubscribeOn中会使用Scheduler切线程。
还有一个疑惑点是在ObservableSubscribeOn的subscribeActual方法中执行了,s.onSubscribe方法,而此时的s类型为ObserveOnObserver,因此,在ObserveOnObserver中会在当前线程执行actual的onSubscribe方法,而这是正确的;但是,我们知道subscribeActual最终会回传到最初的ObservableCreate的subscribeActual方法中,而这里再一次调用了s.onSubscribe方法,那这会不会导致最初的Observer的onSubscribe方法被调用两次?答案是不会,因此此时的s.onSubscribe方法实现位于SubscribeOnObserver中,我们连看看他的方法实现:
// SubscribeOnObserver.java
@Override
public void onSubscribe(Disposable s) {
DisposableHelper.setOnce(this.s, s);
}
// DisposableHelper.java
public static boolean setOnce(AtomicReference<Disposable> field, Disposable d) {
ObjectHelper.requireNonNull(d, "d is null");
if (!field.compareAndSet(null, d)) {
d.dispose();
if (field.get() != DISPOSED) {
reportDisposableSet();
}
return false;
}
return true;
}
可见,上述的onSubscribe方法相当于什么事儿都没做,所以Observer的onSubscribe不会被执行两次。因此,在subscribeOn和observeOn的交界处,往后就都是SubscribeOnObserver了,因此,即使调用多次subscribeOn,Observer的onSubscribe也只会执行一次。
Observer处理流程
观察Observer只需要关注其onNext、onComplete、onError回调即可,以下代码仅仅展示onNext:
// CreateEmitter.java
@Override
public void onNext(T t) {
...
if (!isDisposed()) {
// 直接调用
observer.onNext(t);
}
}
// MapObserver.java
@Override
public void onNext(T t) {
U v;
try {
// 先变换
v = ObjectHelper.requireNonNull(mapper.apply(t), "The mapper function returned a null value.");
}
// 直接调用
actual.onNext(v);
}
// SubscribeOnObserver.java
@Override
public void onNext(T t) {
// 直接调用
actual.onNext(t);
}
// ObserveOnObserver.java
@Override
public void onNext(T t) {
if (done) {
return;
}
if (sourceMode != QueueDisposable.ASYNC) {
queue.offer(t);
}
// 内部切线程并且回调actual的onNext
schedule();
}
可见,Observer在封装过程中,大部分也是直接调用的actual的onNext回调,只有ObserveOnObserver内部会进行线程调度。
subscribeOn如何切换线程
subscribeOn传递的Schedulers.io()负责将Observable.subscribe(Observer)这一动作放在后台线程执行。因此,可以猜测,应该有两步:
- 将Observable.subscribe(Observer)包装到一个Runnable中;
- 将上述Runnable放入到线程中执行。
接下来就看看是如何做到的:
// ObservableSubscribeOn.java
@Override
public void subscribeActual(final Observer<? super T> s) {
final SubscribeOnObserver<T> parent = new SubscribeOnObserver<T>(s);
// 可以看到onSubscribe回调是在UI线程
s.onSubscribe(parent);
parent.setDisposable(scheduler.scheduleDirect(new SubscribeTask(parent)));
}
final class SubscribeTask implements Runnable {
private final SubscribeOnObserver<T> parent;
SubscribeTask(SubscribeOnObserver<T> parent) {
this.parent = parent;
}
@Override
public void run() {
source.subscribe(parent);
}
}
而这里的SubscribeTask是ObservableSubscribeOn的内部类,因此其可以访问到source变量;可以看到,这里正是将source.subscribe(parent)包装到了Runnable中,等待将该Runnable放到线程中执行,第一步已经完成,那么就看看第二步是怎么实现的。
以Schedulers.io()为例,此时的scheduler变量为IOScheduler;而schedulerDirect是父类Scheduler提供的模板方法,在父类中被实现好了:
// Scheduler.java
@NonNull
public Disposable scheduleDirect(@NonNull Runnable run, long delay, @NonNull TimeUnit unit) {
// 此时调用具体子类的createWorker方法
final Worker w = createWorker();
// 这里可以忽略,本质还是将参数run进行包装
final Runnable decoratedRun = RxJavaPlugins.onSchedule(run);
// 再次封装runnable
DisposeTask task = new DisposeTask(decoratedRun, w);
// 使用Worker来执行具体的Runnable封装
w.schedule(task, delay, unit);
return task;
}
==Scheduler顾名思义,是一个调度器,调度什么?就是具体动作的线程调度,即从当前线程调度到目标现成,因此,Scheduler并不是执行目标的地方,其通过scheduleDirect方法调度给了Worker去执行目标Runnable。==可以看到,进行了很多封装,首先是使用IOScheduler的createWorker方法创建Worker,然后就是使用worker的schedule执行任务:
// IOScheduler.java
public Worker createWorker() {
return new EventLoopWorker(pool.get());
}
static final class EventLoopWorker extends Scheduler.Worker {
private final CompositeDisposable tasks;
private final CachedWorkerPool pool;
private final ThreadWorker threadWorker;
final AtomicBoolean once = new AtomicBoolean();
@Override
public Disposable schedule(@NonNull Runnable action, long delayTime, @NonNull TimeUnit unit) {
if (tasks.isDisposed()) {
// don't schedule, we are unsubscribed
return EmptyDisposable.INSTANCE;
}
// 根据注释,知道实际的方法实现位于NewThreadWorker
return threadWorker.scheduleActual(action, delayTime, unit, tasks);
}
}
// 关于该类,只需要记住其是 NewThreadWorker的子类,并且没有覆盖任何父类方法即可
static final class ThreadWorker extends NewThreadWorker
至此,还没有发现封装好的Runnable是如何在其他线程执行的秘密,继续来到NewThreadWorker类:
// NewTheadWorker.java
public ScheduledRunnable scheduleActual(final Runnable run, long delayTime, @NonNull TimeUnit unit, @Nullable DisposableContainer parent) {
Runnable decoratedRun = RxJavaPlugins.onSchedule(run);
ScheduledRunnable sr = new ScheduledRunnable(decoratedRun, parent);
Future<?> f;
try {
if (delayTime <= 0) {
f = executor.submit((Callable<Object>)sr);
} else {
f = executor.schedule((Callable<Object>)sr, delayTime, unit);
}
sr.setFuture(f);
}
return sr;
}
而这里的executor正是一个线程池!!到这里我们终于发现了第二步的实现,正是将Runnable放入了线程池中执行。
observeOn如何切换线程
observeOn负责将onNext、onComplete、onError的回调执行线程切换到UI线程,鉴于onNext中的参数变量通常来自于后台线程,所以,除了方法调用涉及到切换线程,onNext的参数也涉及到跨线程传递;为此,可以猜测,observeOn将相关调用切换回UI线程涉及到三步:
- 将onNext所需的参数保存到一个容器中;
- 将相关调用封装到一个Runnable中等待跨线程调用;
- 跨线程调用封装好的Runnable。
那么就来看看RxJava是如何实现的:
// ObservableObserveOn.java
@Override
protected void subscribeActual(Observer<? super T> observer) {
...
else {
Scheduler.Worker w = scheduler.createWorker();
source.subscribe(new ObserveOnObserver<T>(observer, w, delayError, bufferSize));
}
}
可以发现,模板类似于ObservableSubscribeOn,也是先根据设置的AndroidScheduler.mainThread()的createWorker创建一个Worker,后续的话将worker传递给了ObserveOnObserver。这点和ObservableSubscribeOn不同了,也对,因为想要封装成Runnablel的回调方法位于Observer中,而ObservableObserveOn的subscribeActual还只是一个订阅动作,不涉及到Observer方法回调的事情。
那么就来看看,ObserveOnObserver是如何实现的:
// ObserveOnObserver.java
SimpleQueue<T> queue;
@Override
public void onNext(T t) {
if (done) {
return;
}
if (sourceMode != QueueDisposable.ASYNC) {
// 将主线程回调onNext所需的参数存到了容器queue中
queue.offer(t);
}
schedule();
}
@Override
public void onError(Throwable t) {
if (done) {
RxJavaPlugins.onError(t);
return;
}
error = t;
done = true;
schedule();
}
@Override
public void onComplete() {
if (done) {
return;
}
done = true;
schedule();
}
这里最值得注意的是onNext方法,我们知道,在上一步中Observable.subscribe(Observer)被调用时,其会在执行线程(即IO线程)调用Observer.onNext方法发送数据,此时在ObserveOnObserver中的onNext方法被调用,其将数据T存入了容器queue中。这正体现了我们猜想中的第一步。
还有一点是,在onNext、onError、onComplete的方法最后,都调用了schedule()方法,就看看该方法是如何实现的:
// ObserveOnObserver.java
final Scheduler.Worker worker;
void schedule() {
if (getAndIncrement() == 0) {
worker.schedule(this);
}
}
等等?我们一开始的猜想,这里只完成了第一步,还没将以上回调封装为Runnable的,否则如何跨线程执行呢??一个可疑点是,这里worker.schedule传递的是this!!传递的是ObserveOnObserver对象??我们再细看其内部的方法:
// ObserveOnObserver.java
static final class ObserveOnObserver<T> extends BasicIntQueueDisposable<T>
implements Observer<T>, Runnable {
void drainNormal() {
...
final SimpleQueue<T> q = queue;
final Observer<? super T> a = actual;
for (;;) {
...
for (;;) {
...
try {
// 从容器中取出数据
v = q.poll();
} catch (Throwable ex) {
Exceptions.throwIfFatal(ex);
s.dispose();
q.clear();
a.onError(ex);
worker.dispose();
return;
}
...
a.onNext(v);
}
...
}
}
@Override
public void run() {
...
else {
drainNormal();
}
}
}
可以看到,ObserveOnObserver确实是Runnable的实现类,同时其run方法实现中调用的drainNormal方法正式不断的从共享容器中取出数据,然后执行onNext方法,至此,猜想的第二部也已经完成了,即将三个方法的回调封装到Runnable中以供切回到UI线程执行。
回过头来,AndroidScheduler.mainThread()的createWorker实现如下:
// HandlerScheduler.java
private final Handler handler;
public Worker createWorker() {
return new HandlerWorker(handler);
}
private static final class HandlerWorker extends Worker {
private final Handler handler;
@Override
public Disposable schedule(Runnable run, long delay, TimeUnit unit) {
...
run = RxJavaPlugins.onSchedule(run);
ScheduledRunnable scheduled = new ScheduledRunnable(handler, run);
Message message = Message.obtain(handler, scheduled);
message.obj = this;
handler.sendMessageDelayed(message, unit.toMillis(delay));
...
return scheduled;
}
}
private static final class ScheduledRunnable implements Runnable, Disposable
到此,也发现了第三部,即worker的schedule会将ObserveOnObserver这个Runnable发送到Handler绑定的线程中执行,那么Handler绑定的是主线程吗?
//AndroidScheduler.java
private static final class MainHolder {
// 可见,绑定的正式主线程
static final Scheduler DEFAULT = new HandlerScheduler(new Handler(Looper.getMainLooper()));
}
private static final Scheduler MAIN_THREAD = RxAndroidPlugins.initMainThreadScheduler(
new Callable<Scheduler>() {
@Override public Scheduler call() throws Exception {
return MainHolder.DEFAULT;
}
});
/** A {@link Scheduler} which executes actions on the Android main thread. */
public static Scheduler mainThread() {
return RxAndroidPlugins.onMainThreadScheduler(MAIN_THREAD);
}
Map操作符怎么实现类型转换
source的subscribe方法里面进行onNext方法发送,类型转换的方法位于map参数中,想要实现类型转换,需要捕捉到onNext方法发送的参数,而Observable中onNext方法发送的数据被写在了onSubscribe方法中,是没法拦截的;因此,唯一能够拦截到onNext方法发送的数据的地方只有在Observer的onNext方法接收数据时,因此map操作符发挥作用一定是对Observer进行处理。
// Observable.java
public final <R> Observable<R> map(Function<? super T, ? extends R> mapper) {
ObjectHelper.requireNonNull(mapper, "mapper is null");
// 这里将Observable包装了一下
return RxJavaPlugins.onAssembly(new ObservableMap<T, R>(this, mapper));
}
// ObservableMap.java
final Function<? super T, ? extends U> function;
public ObservableMap(ObservableSource<T> source, Function<? super T, ? extends U> function) {
super(source);
this.function = function;
}
这里先包装Observable实属迫不得已,因为,map方法执行的时候,observe方法还没有被执行,因此,此时还无法获取Observer,只能现将Observable包装一次,这样mapper才能够向后传递,直到遇见Observer。接下来看看ObservableMap的订阅方法:
// ObservableMap.java
public void subscribeActual(Observer<? super U> t) {
// 这里能够获取到Observer了,因此此时才能够将Observer进行包装
source.subscribe(new MapObserver<T, U>(t, function));
}
而ObservableMap 的订阅方法就能够获取到Observer了,此时就能够对Observer进行包装了。
// ObservableMap.java
static final class MapObserver<T, U> extends BasicFuseableObserver<T, U> {
final Function<? super T, ? extends U> mapper;
MapObserver(Observer<? super U> actual, Function<? super T, ? extends U> mapper) {
super(actual);
this.mapper = mapper;
}
@Override
public void onNext(T t) {
...
U v;
try {
// 这里调用mapper的apply方法实现类型的转换
v = ObjectHelper.requireNonNull(mapper.apply(t), "The mapper function returned a null value.");
}
// 将类型转换之后的数据发送出去
actual.onNext(v);
}
...
}
可见mapper的工作原理是:
- 先对参数进行mapper转换;
- 然后调用actual的onNext方法将转换后的数据发送出去。
Disposable机制
有一个问题:当调用了Scheduler.io()之后,那么Disposable如何工作呢?因为任务已经被放到了线程池中执行,此时该如何切断呢?
我们回看一下subscribeOn之后发生了什么:
// ObservableSubscribeOn.java
public void subscribeActual(final Observer<? super T> s) {
final SubscribeOnObserver<T> parent = new SubscribeOnObserver<T>(s);
s.onSubscribe(parent);
// 可见,设置的Disposable是scheduler.scheduleDirect方法的返回值
// 我们假设这里的Scheduler为IOScheduler
parent.setDisposable(scheduler.scheduleDirect(new SubscribeTask(parent)));
}
// Scheduler.java
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);
// 可见返回的Disposable是DisposeTask对象
return task;
}
可见,返回的就是一个DisposeTask对象,那么就要看看该对象的定义:
// Scheduler.java
static final class DisposeTask implements Disposable, Runnable, SchedulerRunnableIntrospection {
final Runnable decoratedRun;
final Worker w;
Thread runner;
DisposeTask(Runnable decoratedRun, Worker w) {
this.decoratedRun = decoratedRun;
this.w = w;
}
@Override
public void run() {
runner = Thread.currentThread();
try {
decoratedRun.run();
} finally {
dispose();
runner = null;
}
}
@Override
public void dispose() {
// 可见,在Scheduler为IOScheduler的情况下,其Worker就是NewThreadWorker
// 此时,dispose方法的作用就是执行Worker的shutdown方法
if (runner == Thread.currentThread() && w instanceof NewThreadWorker) {
((NewThreadWorker)w).shutdown();
} else {
w.dispose();
}
}
....
}
// NewThreadWorker.java
public void shutdown() {
if (!disposed) {
disposed = true;
// 关闭线程池
executor.shutdown();
}
}
可见,在Scheduler为IoScheduler的情况下,获取到的Disposable的dispose方法就是关闭线程池。
问题解答
以以下调用为例:
source.subscribeOn(Scheduler1).subscribeOn(Scheduler2).observeOn(Scheduler.a).observeOn(Scheduler.b).observe(actual)
相关对象如下:
Observable:
source
observable1 : thread1
observable2 : thread2
Obeserver:
observer-a : thread-a
observer-b : thread-b
actual
多次subscribeOn只有第一次生效
在发生subscribe时,observable2的subscribeActual首先被调用,其将source2.subscribe()动作分发到了thread2中执行,注意这里的source2正是observable1;因此,方法调用来到啦observable1的subscribeActual,其将source1.subscribe()动作分发到了thread1中执行,注意这里的source1正是source对象,所以我们在初始化时定义的subscribe实现就是在thread1中被调用,因此说,只有第一次subscribeOn有效。
多次observeOn只有最后一次生效
在发生subscribe时,observer-a的三个方法回调被分发到了thread-a中,从而触发actual-a的三个方法回调,而这里的actual-a正是observer-b对象;因此,方法调用来到了observer-b中,同样,observer-b会将三个方法回调分发到thread-b中执行,从而触发actual-b的三个方法回调,而这里的actual-b正是最终的actual,所以我们在初始化时定义的onNext、onComplete、onError方法正是在thread-b中被调用,因此说,只有最后一次observerOn有效。