一 前言
基于RxJava2.1.1
我们在前面的 Rxjava 2 的源码解析初步分析了RxJava从创建到执行的流程,分析了RxJava的随意终止Reactive流的能力的来源;也明白了RxJava的onComplete();与onError(t);只有一个会被执行的秘密。RxJava2.X 源码分析(二)中探索了RxJava2调用subscribeOn切换被观察者线程的原理。
本次我们将继续探索RxJava2.x切换观察者的原理,分析observeOn与subscribeOn的不同之处。继续实现我们在第一篇中定下的小目标
二 从Demo到原理
这里就不粘贴代码了,大家可以去RxJava2.X 源码分析(二 )这里看demo,我们直接来看observeOn这个方法:
Class Obsevable{
......
@CheckReturnValue
@SchedulerSupport(SchedulerSupport.CUSTOM)
public final Observable<T> observeOn(Scheduler scheduler) {
//false为默认无延迟发送错误,bufferSize为缓冲区大小
return observeOn(scheduler, false, bufferSize());
}
@CheckReturnValue
@SchedulerSupport(SchedulerSupport.CUSTOM)
public final Observable<T> observeOn(Scheduler scheduler, boolean delayError, int bufferSize) {
ObjectHelper.requireNonNull(scheduler, "scheduler is null");
ObjectHelper.verifyPositive(bufferSize, "bufferSize");
return RxJavaPlugins.onAssembly(new ObservableObserveOn<T>(this, scheduler, delayError, bufferSize));
}
......
}
看到这里其实大家也应该猜到了,observeOn和subscribeOn执行流程基本都是一样的,都是传入原被观察者已经线程调度器,通过最后的subribe()方法,调用了原被观察者的包装类(ObservableObserveOn)中的subscribeActual()方法,在此方法中对传入的原观察者进行一次包装,其次根据传入的线程调度器,实现线程的切换,同时在Runeable的run方法中调用原被观察者的subribe(),执行原被观察者的subscribeActual()方法,同时执行原观察者的包装类里的方法(里面封装了原观察者的方法)。我们接下来看看是否是这样的原理:
先来看看ObservableObserveOn:
很显然,ObservableObserveOn其实就是一个Obserable,即是被观察者的包装类,接着我们在来看看里面的subscribeActual()方法:
@Override
protected void subscribeActual(Observersuper T> observer) {
//1、在当前线程调度,但不是立即执行,放入队列中
if (scheduler instanceof TrampolineScheduler) {
source.subscribe(observer);
} else {
//2、本次走的是这里
Scheduler.Worker w = scheduler.createWorker();
//3
source.subscribe(new ObserveOnObserver<T>(observer, w, delayError, bufferSize));
}
}
Ok,果然,熟悉的模式,对我们上游的Observable,下游的Observerwrapper一次。
1、ObservableObserveOn继承了AbstractObservableWithUpstream
2、source保存上游的Observable
3、scheduler为本次的调度器
4、在下游调用subscribe订阅时触发->subscribeActual->Wrapper了下游的Observer观察者
3处:source为上游Observable(原Observable),下游Observer(原Observer)被wrapper到ObserveOnObserver,发生订阅数件,上游Observable(原Observable)开始执行subscribeActual,调用ObserveOnObserver的onSubscribe以及onNext、onError、onComplete等
OK,我们接着看Observer被包装进 ObserveOnObserver的样子,代码有点多,我们分段讲解:
先来看看 onSubscribe方法:
Class ObservableObserveOn{
static final class ObserveOnObserver<T> extends BasicIntQueueDisposable<T>
implements Observer<T>, Runnable {
private static final long serialVersionUID = 6576896619930983584L;
//下游的Observer
final Observersuper T> actual;
//调度工作者
final Scheduler.Worker worker;
//是否延迟错误,默认false
final boolean delayError;
//队列大小
final int bufferSize;
//存储上游Observable下发的数据队列
SimpleQueue<T> queue;
//存储下游Observer的Disposable
Disposable s;
//存储错误信息
Throwable error;
//校验是否完毕
volatile boolean done;
//是否被取消
volatile boolean cancelled;
//存储执行模式,同步或者异步 同步
int sourceMode;
boolean outputFused;
ObserveOnObserver(Observersuper T> actual, Scheduler.Worker worker, boolean delayError, int bufferSize) {
this.actual = actual;
this.worker = worker;
this.delayError = delayError;
this.bufferSize = bufferSize;
}
@Override
public void onSubscribe(Disposable s) {
if (DisposableHelper.validate(this.s, s)) {
this.s = s;
if (s instanceof QueueDisposable) {
@SuppressWarnings("unchecked")
QueueDisposable<T> qd = (QueueDisposable<T>) s;
int m = qd.requestFusion(QueueDisposable.ANY | QueueDisposable.BOUNDARY);
//1、判断执行模式并调用onSubscribe传递给下游Observer
if (m == QueueDisposable.SYNC) {
sourceMode = m;
queue = qd;
//true 后面的onXX方法都不会被调用
done = true;
actual.onSubscribe(this);
//2、同步模式下,直接调用schedule
schedule();
return;
}
if (m == QueueDisposable.ASYNC) {
sourceMode = m;
queue = qd;
actual.onSubscribe(this);
//2、异步模式下,等待schedule
return;
}
}
queue = new SpscLinkedArrayQueue<T>(bufferSize);
//判断执行模式并调用onSubscribe传递给下游Observer
actual.onSubscribe(this);
}
}
........
}
OK,执行玩这里之后,就到我们的onNext方法了:
@Override
public void onNext(T t) {
//3、数据源是同步模式或者执行过error / complete 会是true
if (done) {
return;
}
//如果数据源不是异步类型,
if (sourceMode != QueueDisposable.ASYNC) {
//4、上游Observable下发的数据压入queue
queue.offer(t);
}
//5、开始调度
schedule();
}
其次只能触发一次的onError,基本差不多
@Override
public void onError(Throwable t) {
if (done) {
//6、已完成再执行会抛一场
RxJavaPlugins.onError(t);
return;
}
//7、记录错误信息
error = t;
//8、标识已完成
done = true;
//9、开始调度
schedule();
}
同样是只能触发一次的onComplete,同样的套路,就不说了
@Override
public void onComplete() {
if (done) {
return;
}
done = true;
schedule();
}
我们重点来看一下schedule()这个方法:
void schedule() {
if (getAndIncrement() == 0) {
worker.schedule(this);
}
}
这里调用的是worker(也就是我们在ObserverOn方法里指定的线程)中的schedule()方法,其中的参数是一个Runnable类型,传入的是this,说明观察者的包装类(ObserveOnObserver)是实现了Runnable接口的:
static final class ObserveOnObserver<T> extends BasicIntQueueDisposable<T>
implements Observer<T>, Runnable
接下看,继续调用 schedule( Runnable action, long delayTime, TimeUnit unit) 方法,但是这个方法是个抽象方法,这里我们就假设这里这个 worker 是 IO 线程,所以我直接贴 IoScheduler 的代码了:
public Disposable schedule(@NonNull Runnable action, long delayTime, @NonNull TimeUnit unit) {
if (tasks.isDisposed()) {
// don't schedule, we are unsubscribed
return EmptyDisposable.INSTANCE;
}
return threadWorker.scheduleActual(action, delayTime, unit, tasks);
}
然后再贴一下 scheduleActual 的方法:
public ScheduledRunnable scheduleActual(final Runnable run, long delayTime, @NonNull TimeUnit unit, @Nullable DisposableContainer parent) {
Runnable decoratedRun = RxJavaPlugins.onSchedule(run);
//就是个 Runnable
ScheduledRunnable sr = new ScheduledRunnable(decoratedRun, parent);
if (parent != null) {
if (!parent.add(sr)) {
return sr;
}
}
Future<?> f;
try {
//判断延迟时间,然后使用线程池运行 Runnable
if (delayTime <= 0) {
f = executor.submit((Callable<Object>)sr);
} else {
f = executor.schedule((Callable<Object>)sr, delayTime, unit);
}
sr.setFuture(f);
} catch (RejectedExecutionException ex) {
if (parent != null) {
parent.remove(sr);
}
RxJavaPlugins.onError(ex);
}
return sr;
}
这样一来就会在相应的线程中运行 ObserveOnObserver 的 run 方法:
Class ObserveOnObserver {
......
public void run() {
if (outputFused) {
drainFused();
} else {
drainNormal();
}
}
......
}
好吧,在看drainNormal前,我们先看一个函数checkTerminated():
//从名字看是检测是否已终止
boolean checkTerminated(boolean d, boolean empty, Observersuper T> a) {
//1、订阅已取消
if (cancelled) {
//清空队列
queue.clear();
return true;
}
//2、d其实是done,
if (d) {
//done==ture可能的情况onNext刚被调度完,onError或者onCompele被调用,
Throwable e = error;
if (delayError) {
//delayError==true时等到队列为空才调用
if (empty) {
if (e != null) {
a.onError(e);
} else {
a.onComplete();
}
worker.dispose();
return true;
}
} else {
//否则直接调用
if (e != null) {
queue.clear();
a.onError(e);
worker.dispose();
return true;
} else
if (empty) {
a.onComplete();
worker.dispose();
return true;
}
}
}
//否则未终结
return false;
}
true:1、订阅被取消cancelledtrue,2、donetrue onNext刚被调度完,onError或者onCompele被调用
继续看drainNormal:
void drainNormal() {
int missed = 1;
final SimpleQueue<T> q = queue;
final Observersuper T> a = actual;
//Ok,死循环,我们来看下有哪些出口
for (;;) {
//Ok,出口,该方法前面分析的
if (checkTerminated(done, q.isEmpty(), a)) {
return;
}
//再次死循环
for (;;) {
boolean d = done;
T v;
try {
//分发数据出队列
v = q.poll();
} catch (Throwable ex) {
//有异常时终止退出
Exceptions.throwIfFatal(ex);
s.dispose();
q.clear();
a.onError(ex);
//停止worker(线程)
worker.dispose();
return;
}
boolean empty = v == null;
//判断队列是否为空
if (checkTerminated(d, empty, a)) {
return;
}
//没数据退出
if (empty) {
break;
}
//数据下发给下游Obsever,这里支付者onNext,onComplete和onError主要放在了checkTerminated里面回调
a.onNext(v);
}
//保证此时确实有一个 worker.schedule(this);正在被执行,
missed = addAndGet(-missed);
//为何要这样做呢?我的理解是保证drainNormal方法被原子性调用,如果执行了addAndGet之后getAndIncrement() == 0就成立了,此时又一个worker.schedule(this);被调用了,那么就不能执行break了
if (missed == 0) {
break;
}
}
}
总结
Ok,看到这里我们基本了解了observeOn的实现流程,同样是老套路,使用装饰者模式,中间Wrapper了我们的Observable和Observer,通过中间增加一个Observable和Observer来实现线程的切换。