RxJava2源码解析
一、简介
RxJava是一款基于事件流的链式调用,支持切换线程,使用简单。
接下来,会根据RxJava2版本进行分析。本文不会讲具体详细的操作符使用,主要从下面几个问题去看待源码是如何设计实现的
- 怎么做到响应事件发射源发出的消息
- 如何通过简单操作符达到切换线程的
- 为什么发射源只支持第一次线程切换,而订阅者可以多次切换线程
先对下文的一些名词做说明:
- 发射源 = 被观察者
- 订阅者 = 观察者
二、从代码看设计
1、核心设计–观察者模式
先从简单的实现来看
//创建发射源(被观察者)
Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
emitter.onNext(1);
emitter.onNext(2);
emitter.onNext(3);
emitter.onComplete();
}
})
//切换发射源线程
.subscribeOn(Schedulers.io())
//切换订阅者线程
.observeOn(AndroidSchedulers.mainThread())
//订阅消息(观察者)
.subscribe(new Observer<Integer>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(Integer integer) {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
});
从链式调用上,我们看起来像是Observable订阅了Observer,实际上我们需要返过来看,是Observable被Observer订阅。接下来我们先从订阅方法分析
public abstract class Observable<T> implements ObservableSource<T> {
@SchedulerSupport(SchedulerSupport.NONE)
@Override
public final void subscribe(Observer<? super T> observer) {
//校验空
ObjectHelper.requireNonNull(observer, "observer is null");
try {
//hook类
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) {
Exceptions.throwIfFatal(e);
// can't call onError because no way to know if a Disposable has been set or not
// can't call onSubscribe because the call might have set a Subscription already
RxJavaPlugins.onError(e);
NullPointerException npe = new NullPointerException("Actually not, but can't throw other exceptions due to RS");
npe.initCause(e);
throw npe;
}
}
//抽象方法,需要到达订阅者之前的所有操作类实现重写
protected abstract void subscribeActual(Observer<? super T> observer);
}
接下来,我们先忽略中间的线程切换符号,来看一看发射源的实现
public abstract class Observable<T> implements ObservableSource<T> {
@CheckReturnValue
@NonNull
@SchedulerSupport(SchedulerSupport.NONE)
public static <T> Observable<T> create(ObservableOnSubscribe<T> source) {
//判空
ObjectHelper.requireNonNull(source, "source is null");
//将接口包装成ObservableCreate,而ObservableCreate是Observable的子类
return RxJavaPlugins.onAssembly(new ObservableCreate<T>(source));
}
}
public final class ObservableCreate<T> extends Observable<T> {
final ObservableOnSubscribe<T> source;
//传入发射元数据接口对象
public ObservableCreate(ObservableOnSubscribe<T> source) {
this.source = source;
}
//该方法就是通知观察者的具体实现。
@Override
protected void subscribeActual(Observer<? super T> observer) {
//构造发射器并传入观察者,方便在发射器内部通知观察者
CreateEmitter<T> parent = new CreateEmitter<T>(observer);
//首先通知观察者Dispose对象,CreateEmitter实现了Disposable接口,外部可以通过dispose()方法来取消发射器发射数据,内部DisposableHelper.setOnce保证只调用一次
observer.onSubscribe(parent);
try {
//将发射器交给发射源接口发送数据,需外部手动实现,例如上面离职create里的subscribe方法里的onNext()等
source.subscribe(parent);
} catch (Throwable ex) {
Exceptions.throwIfFatal(ex);
parent.onError(ex);
}
}
//静态内部类发射器
static final class CreateEmitter<T>
extends AtomicReference<Disposable>
implements ObservableEmitter<T>, Disposable {
private static final long serialVersionUID = -3434801548987643227L;
final Observer<? super T> observer;
//构造函数-传入观察者
CreateEmitter(Observer<? super T> observer) {
this.observer = observer;
}
//
@Override
public void onNext(T t) {
//发射数据不能为空
if (t == null) {
onError(new NullPointerException("onNext called with null. Null values are generally not allowed in 2.x operators and sources."));
return;
}
//如果没有调用dispose取消发送,则通知观察者
if (!isDisposed()) {
observer.onNext(t);
}
}
@Override
public void onError(Throwable t) {
//先尝试发送错误信息,未发送者hook处理
if (!tryOnError(t)) {
RxJavaPlugins.onError(t);
}
}
@Override
public boolean tryOnError(Throwable t) {
//error不能为空
if (t == null) {
t = new NullPointerException("onError called with null. Null values are generally not allowed in 2.x operators and sources.");
}
//如果没有调用dispose取消发送,则通知观察者
if (!isDisposed()) {
//通知错误之后,取消发送,这就是为什么错误回调之后,会停止发送的原因
try {
observer.onError(t);
} finally {
dispose();
}
return true;
}
return false;
}
@Override
public void onComplete() {
if (!isDisposed()) {
//通知完成之后,取消发送,这就是为什么完成回调之后,会停止发送的原因
try {
observer.onComplete();
} finally {
dispose();
}
}
}
@Override
public void setDisposable(Disposable d) {
//dispose帮助类,传入原子索引类来控制
DisposableHelper.set(this, d);
}
@Override
public void setCancellable(Cancellable c) {
setDisposable(new CancellableDisposable(c));
}
@Override
public ObservableEmitter<T> serialize() {
return new SerializedEmitter<T>(this);
}
@Override
public void dispose() {
DisposableHelper.dispose(this);
}
@Override
public boolean isDisposed() {
return DisposableHelper.isDisposed(get());
}
······
}
······
}
至此我们明白了RxJava源码是根据观察者模式主线来实现的。
同时能回答我们提出的第一个问题:
- 怎么做到响应事件发射源发出的消息
通过调用subscribe方法,再实际调用subscribeActual(obserser)将观察者对象传给被观察者,这样被观察者有变动就能通知到观察者
2、锦上添花–装饰者模式
为了弄懂线程切换原理,我们以装饰者模式的角度,更易理解是怎么样切换的
2.1 发射源切换线程
先从发射源先从切换分析subscribeOn
public abstract class Observable<T> implements ObservableSource<T> {
@CheckReturnValue
@SchedulerSupport(SchedulerSupport.CUSTOM)
public final Observable<T> subscribeOn(Scheduler scheduler) {
//校验空
ObjectHelper.requireNonNull(scheduler, "scheduler is null");
//构建ObservableSubscribeOn对象,并传入发射源和线程调度器
return RxJavaPlugins.onAssembly(new ObservableSubscribeOn<T>(this, scheduler));
}
}
public final class ObservableSubscribeOn<T> extends AbstractObservableWithUpstream<T, T> {
final Scheduler scheduler;
public ObservableSubscribeOn(ObservableSource<T> source, Scheduler scheduler) {
super(source);
this.scheduler = scheduler;
}
@Override
public void subscribeActual(final Observer<? super T> observer) {
//传入观察者,包装成Dispose对象
final SubscribeOnObserver<T> parent = new SubscribeOnObserver<T>(observer);
//通知观察者onSubscribe
observer.onSubscribe(parent);
//设置Disposable,并设置发射器,对应的线程调度器scheduler执行scheduleDirect方法传入Runnable接口对象来运行
parent.setDisposable(scheduler.scheduleDirect(new SubscribeTask(parent)));
}//前面有讲到,这个方法是到达观察者之前都要实现的,实际订阅执行的地方
//内部类,实现了Runnable接口
final class SubscribeTask implements Runnable {
private final SubscribeOnObserver<T> parent;
SubscribeTask(SubscribeOnObserver<T> parent) {
this.parent = parent;
}
@Override
public void run() {
//在run方法中观察者订阅被观察者,该方法运行到哪个线程就会在哪个线程发送数据
//同时也会影响观察者的调用线程
source.subscribe(parent);
}
}
······
}
public abstract class Scheduler {
@NonNull
public Disposable scheduleDirect(@NonNull Runnable run) {
//会在调用三个参数的方法
return scheduleDirect(run, 0L, TimeUnit.NANOSECONDS);
}
//默认实现是当前线程
@NonNull
public Disposable scheduleDirect(@NonNull Runnable run, long delay, @NonNull TimeUnit unit) {
//创建工作者,抽象方法
final Worker w = createWorker();
//hook调用
final Runnable decoratedRun = RxJavaPlugins.onSchedule(run);
//默认Run方法,运行在当前线程
DisposeTask task = new DisposeTask(decoratedRun, w);
//在对应线程执行任务
w.schedule(task, delay, unit);
return task;
}
}
下面就以AndroidSchedulers.mainThread()来做分析
public final class AndroidSchedulers {
private static final class MainHolder {
//构造出默认的主线程Handler来切换线程
static final Scheduler DEFAULT
= new HandlerScheduler(new Handler(Looper.getMainLooper()), false);
}
private static final Scheduler MAIN_THREAD = RxAndroidPlugins.initMainThreadScheduler(
new Callable<Scheduler>() {
@Override public Scheduler call() throws Exception {
return MainHolder.DEFAULT;
}
});
/** 获取一个主线程执行动作的Scheduler */
public static Scheduler mainThread() {
//获取MAIN_THREAD,实际处理是HandlerScheduler
return RxAndroidPlugins.onMainThreadScheduler(MAIN_THREAD);
}
}
final class HandlerScheduler extends Scheduler {
private final Handler handler;
private final boolean async;
HandlerScheduler(Handler handler, boolean async) {
this.handler = handler;
this.async = async;
}
@Override
@SuppressLint("NewApi")
//直接订阅执行的地方
public Disposable scheduleDirect(Runnable run, long delay, TimeUnit unit) {
if (run == null) throw new NullPointerException("run == null");
if (unit == null) throw new NullPointerException("unit == null");
//hook方法run先处理
run = RxJavaPlugins.onSchedule(run);
//包装成ScheduledRunnable对象
ScheduledRunnable scheduled = new ScheduledRunnable(handler, run);
//async默认为false,构建非异步消息并延迟发视频发送。之后Message就会在主线程调用run()方法处理消息内容
Message message = Message.obtain(handler, scheduled);
if (async) {
message.setAsynchronous(true);
}
handler.sendMessageDelayed(message, unit.toMillis(delay));
return scheduled;
}
}
/**
* 回到SubscribeTask类,就会执行该类的run()方法,发射源就在这里运行
**/
final class SubscribeTask implements Runnable {
private final SubscribeOnObserver<T> parent;
SubscribeTask(SubscribeOnObserver<T> parent) {
this.parent = parent;
}
@Override
public void run() {
//再run方法中观察者订阅被观察者,该方法运行到哪个线程就会在哪个线程发送数据
source.subscribe(parent);
}
}
那我们深入想一想,假如有多个subscribeOn
run()方法里的source是同一个,按照链式调用顺序,包装类是跟链式调用时相反方向的,意思就是会先调用最后一个设置的subscribeOn的方法,这个时候发射源没有发射数据,在调用包装之前的subscribeOn,层层朝内层包装调用,最后达到切换线程的就是第一个subscribeOn设置的run()方法里。
如下图
2.2 订阅者切换线程
我们从ObserverOn开始看
public abstract class Observable<T> implements ObservableSource<T> {
@CheckReturnValue
@SchedulerSupport(SchedulerSupport.CUSTOM)
public final Observable<T> observeOn(Scheduler scheduler) {
//调用三个参数方法,默认不延时发送错误
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");
//构建ObservableObserveOn对象并传入发射源和线程调度器等
return RxJavaPlugins.onAssembly(new ObservableObserveOn<T>(this, scheduler, delayError, bufferSize));
}
}
public final class ObservableObserveOn<T> extends AbstractObservableWithUpstream<T, T> {
final Scheduler scheduler;
final boolean delayError;
final int bufferSize;
public ObservableObserveOn(ObservableSource<T> source, Scheduler scheduler, boolean delayError, int bufferSize) {
super(source);
this.scheduler = scheduler;
this.delayError = delayError;
this.bufferSize = bufferSize;
}
@Override
protected void subscribeActual(Observer<? super T> observer) {
//如果在默认当前线程工作,直接订阅
if (scheduler instanceof TrampolineScheduler) {
source.subscribe(observer);
} else {
//创建线程调度对应的工作者
Scheduler.Worker w = scheduler.createWorker();
//在当前线程或者第一个subscribeOn指定的线程订阅,构建ObserveOnObserver(内部类)对象传入工作者和观察者,一遍在指定线程通知观察者
//从这里已经能说明,当前的subscribeOn影响的是之后的一个订阅事件
source.subscribe(new ObserveOnObserver<T>(observer, w, delayError, bufferSize));
}
}
static final class ObserveOnObserver<T> extends BasicIntQueueDisposable<T>
implements Observer<T>, Runnable {
······
private static final long serialVersionUID = 6576896619930983584L;
ObserveOnObserver(Observer<? super T> actual, Scheduler.Worker worker, boolean delayError, int bufferSize) {
this.downstream = actual;
this.worker = worker;
this.delayError = delayError;
this.bufferSize = bufferSize;
}
@Override
public void onNext(T t) {
//已经结束发送直接返回
if (done) {
return;
}
//非异步模式,加入队列
if (sourceMode != QueueDisposable.ASYNC) {
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();
}
//实际执行的方法
void schedule() {
if (getAndIncrement() == 0) {
//线程调度对应的工作者在自己线程执行run()回调,下方依然以主线程来举例
worker.schedule(this);
}
}
@Override
public void run() {
//实际开始执行回调方法,根据不同情况执行onNext、onError、onComplete等回调
//这里不继续查看详细判断,与这次主题关联就不大
if (outputFused) {
drainFused();
} else {
drainNormal();
}
}
}
······
}
接下来看,mainThread是怎么达到切换线程的目的的
//Scheduler#Worker
//这个是调度器对应的执行工作者,需要子类自己去实现创建,和具体执行事情的方法
public abstract class Scheduler {
@NonNull
public abstract Worker createWorker();
public abstract static class Worker implements Disposable {
@NonNull
public Disposable schedule(@NonNull Runnable run) {
return schedule(run, 0L, TimeUnit.NANOSECONDS);
}
@NonNull
public abstract Disposable schedule(@NonNull Runnable run, long delay, @NonNull TimeUnit unit);
}
}
//上面我们也讲到主线程的Scheduler对应的是HandlerScheduler
final class HandlerScheduler extends Scheduler {
@Override
public Worker createWorker() {
//创建主线程handler工作者
return new HandlerWorker(handler, async);
}
private static final class HandlerWorker extends Worker {
private final Handler handler;
private final boolean async;
private volatile boolean disposed;
HandlerWorker(Handler handler, boolean async) {
this.handler = handler;
this.async = async;
}
@Override
@SuppressLint("NewApi")
public Disposable schedule(Runnable run, long delay, TimeUnit unit) {
//校验参数
if (run == null) throw new NullPointerException("run == null");
if (unit == null) throw new NullPointerException("unit == null");
//如果已经dispose,则取消
if (disposed) {
return Disposables.disposed();
}
//hook调用
run = RxJavaPlugins.onSchedule(run);
//包装成ScheduledRunnable对象
ScheduledRunnable scheduled = new ScheduledRunnable(handler, run);
//发送消息,等待消息队列取出执行scheduled的run()方法,由于上一节说过handler是主线程的handler,所以run()方法在线程执行,就达到了切换的效果
Message message = Message.obtain(handler, scheduled);
message.obj = this; // Used as token for batch disposal of this worker's runnables.
if (async) {
message.setAsynchronous(true);
}
handler.sendMessageDelayed(message, unit.toMillis(delay));
// 重新检查已处置状态以将其删除,以防万一我们正在争夺对dispose()的调用。
if (disposed) {
handler.removeCallbacks(scheduled);
return Disposables.disposed();
}
return scheduled;
}
@Override
public void dispose() {
disposed = true;
handler.removeCallbacksAndMessages(this /* token */);
}
@Override
public boolean isDisposed() {
return disposed;
}
}
}
至此,能明白观察者是怎么切换线程来回调,接下来分析为什么观察者可以多次切换线程
上面再ObservableObserveOn的subscribeActual方法中以及之后的分析,能判断出,下方的订阅事件只受最近的一次observeOn影响(即使调用多次observeOn)。由于中途可能存在map、filter、flatMap等转换,这些均会受调用它之前设置的observeOn线程影响。所以observeOn可以多次生效,但是连续调用,也只有转换或订阅之前最近一次的生效。
如下图
上面的第二、三问题也能够回答了
-
如何通过简单操作符达到切换线程的
通过包装类,将source发送源和observer订阅者通过线程调度器包装一次,来达到切换的效果 -
为什么发射源只支持第一次线程切换,而订阅者可以多次切换线程
通过多次包装类,发射源只有包装的最里层的线程切换是实际运行的线程。
订阅者可以通过层层包装转换,切换线程,影响之后的转换或者订阅的线程。所以只要不是连续调用,就会有多次切换生效。但是如果是连续调用,则处理消息之前最近的一次生效
总结
这里仅仅分析了核心的设计,未涉及到具体操作符的执行,也未涉及到具体元数据的发送流情况,如果感兴趣,读者可以自行查看。我将在有时间时补充这部分。