一、前言
关于 RxJava 的使用推荐大家看这篇文章 RxJava2 只看这一篇文章就够了。
二、订阅
首先我们先分析一个最简单的示例,代码如下:
Observable.create(new ObservableOnSubscribe<String>() {
@Override
public void subscribe(ObservableEmitter<String> emitter) throws Exception {
emitter.onNext("1");
emitter.onNext("2");
emitter.onNext("3");
emitter.onComplete();
}
}).subscribe(new Observer<String>() {
@Override
public void onSubscribe(Disposable d) {
Log.e("TAG", "onSubscribe(): ");
}
@Override
public void onNext(String s) {
Log.e("TAG", "onNext(): " + s);
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
Log.e("TAG", "onComplete(): ");
}
});
既然要了解 RxJava,那么必不可少的我们应该先来看看他的入口类,也就是 Observable:
//Observable.java
public abstract class Observable<T> implements ObservableSource<T> {
@Override //实现了ObservableSource的方法
public final void subscribe(Observer<? super T> observer) {
//省略一堆判空等处理
subscribeActual(observer);
}
@Override //交由子类实现的出现方法
protected abstract void subscribeActual(Observer observer) ;
}
省略了一堆静态方法之后我们可以看到 Observable 是一个抽象类,实现了 ObservableSource 接口,并留了 subscribeActual() 这个抽象方法。ObservableSource 接口只定义了一个 subscribe() 方法,可以看到这个方法做了一些基础判断之后直接跳转到子类的 subscribeActual() 方法。所以一个被观察者被 subscribe() 的逻辑其实是交由 Observable 子类来实现的,每个不同的被观察者可以根据自己的需求实现 "被订阅" 后的操作。
接下来是如何生成一个 Obserable 对象,我们看到 create() 方法。create() 方法便是 Obserable 其中一个关键的静态方法。我们跟进去看一下 create() 方法源码:
//Observable.java
public static <T> Observable<T> create(ObservableOnSubscribe<T> source) {
ObjectHelper.requireNonNull(source, "source is null");
return RxJavaPlugins.onAssembly(new ObservableCreate<T>(source));
}
首先第一句代码是对传入的对象进行判空,内部实现是如果传入 null 会抛异常。接着是生成一个 ObservableCreate 对象,然后将这个对象传入 RxJavaPlugins 进行组装。RxJavaPlugins 提供了一系列的 Hook function,通过钩子函数这种方法对 RxJava 的标准操作进行加工,当我们没有进行配置时,默认是直接返回原来的对象,也就是返回 ObservableCreate 对象。(为了方便讲解,后续将直接忽视判空和 RxJavaPlugins 的代码)
//ObservableCreate.java
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);
observer.onSubscribe(parent);
try {
source.subscribe(parent);
} catch (Throwable ex) {
Exceptions.throwIfFatal(ex);
parent.onError(ex);
}
}
从上述方法可以看出 ObservableCreate 是 Observable 的一个子类,我们自定义的 ObservableOnSubscribe 作为一个名为 source 字段被传入了。事实上在 Observable 的子类实现中,它们都有一个名为 source 的字段,指代上游 Observable(实际上是 ObservableOnSubscribe,但是我们不妨理解成就是 Observable)。
我们看下 subcribeActual() 方法中第 1 行代码的 CreateEmitter:
//ObservableCreate.java
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;
}
if (!isDisposed()) {
observer.onNext(t);
}
}
......
可以看到 CreateEmitter 实现了 ObservableEmitter 和 Disposable 接口。
在 subscribeActual() 的第 5 行调用了 Observer#onSubscribe(Disposable) ,所以我们可以知道 Observer#onSubscribe(Disposable) 是先被调用的,而此时 Observable 甚至还没有开始发射事件!接下来就是调用了 source.subscribe(ObservableEmitter),这个方法是交由开发者去实现的,在示例代码是如下:
@Override
public void subscribe(ObservableEmitter<String> emitter) throws Exception {
emitter.onNext("1");
emitter.onNext("2");
emitter.onNext("3");
emitter.onComplete();
}
这个 ObservableEmitter 就是我们在上面创建 createEmitter,我们可以看到它的 onNext() 方法中会先判断参数是否为空,为空的话会直接调用 onError() 方法,接着会调用 isDisposed() 方法来判断是否处于 disposed 状态,如果不是的话才会去调用 observer 的 onNext() 方法。也就是示例代码中的:
@Override
public void onNext(String s) {
Log.e("TAG", "onNext(): " + s);
}
逻辑有点饶,这里我画了一个流程图大家可以参考一下帮助理解:
至此,基本订阅流程我们就理清楚了。我们从 Observable#subscribe(Observer) 开始,将 Observer 传给 Observable,而 Observable 又会在 onNext(T) 方法中激活 Observer 的 onNext(T) 方法。我们在示例只涉及了少量的 Observable 和 Observer,事实上,我们在 RxJava 中运用的操作符都会在内部创建一个 Observable 和 Observer,虽然在 Observable#subscribeActual(Observer) 中都有自己特定的实现,但是它们大部分都是做两个操作,一是将「下游」传来的 Observer 根据需求进行封装;二就是让「上游」的 Observable subscribe() 该 Observer。
三、操作符
现在我们来看一个复杂一点的示例。下面代码的前提是定义了一个 login 接口,返回值为 { isSuccess, UserInfo}。代码如下:
Observable.create(new ObservableOnSubscribe<LoginApiResult>() {
@Override
public void subscribe(ObservableEmitter<LoginApiResult> e) throws Exception {
e.onNext(login());
}
}) //调用登录接口
.map(new Function<LoginApiBean, UserInfoBean>() {
@Override
protected UserInfoBean decode(LoginApiBean loginApiBean) {
//处理登录结果,返回UserInfo
if (loginApiBean.isSuccess()) {
return loginApiBean.getUserInfoBean();
} else {
throw new RequestFailException("获取网络请求失败");
}
}
})
.doOnNext(new Consumer<UserInfoBean>() {
@Override
public void accept(@NonNull UserInfoBean bean) throws Exception {
//保存登录结果UserInfo
saveUserInfo(bean);
}
})
.subscribeOn(Schedulers.io()) //调度线程
.observeOn(AndroidSchedulers.mainThread()) //调度线程
.subscribe(new Consumer<UserInfoBean>() {
@Override
public void accept(@NonNull UserInfoBean bean) throws Exception {
//整个请求成功,根据获取的UserInfo更新对应的View
showSuccessView(bean);
}
}, new Consumer<Throwable>() {
@Override
public void accept(@NonNull Throwable throwable) throws Exception {
//请求失败,显示对应的View
showFailView();
}
});
首先是任务链的构建,我们先看一下 create() 方法:
//Observable.java
public static <T> Observable<T> create(ObservableOnSubscribe<T> source) {
ObjectHelper.requireNonNull(source, "source is null");
return RxJavaPlugins.onAssembly(new ObservableCreate<T>(source));
}
返回 ObservableCreate,继续跟进去看看:
//ObservableCreate.java
public final class ObservableCreate<T> extends Observable<T> {
final ObservableOnSubscribe<T> source;
public ObservableCreate(ObservableOnSubscribe<T> source) {
this.source = source;
}
...
}
这个类继承了 Observable 类,并存储了我们刚才传进去的 ObservableOnSubscribe 对象。往下,我们调用了 Obserable 的 map() 方法,我们跟进去看一下 map() 方法:
//Observable.java
public final <R> Observable<R> map(Function<? super T, ? extends R> mapper) {
ObjectHelper.requireNonNull(mapper, "mapper is null");
return RxJavaPlugins.onAssembly(new ObservableMap<T, R>(this, mapper));
}
可以看到其实是返回了一个 ObservableMap 对象,接受了两个参数,一个是 this,在这里指的也就是刚才的 ObservableCreate ,还有一个 Function 对象,我们再跟进去看一下 ObservableMap 的基础信息:
//ObservableMap.java
public final class ObservableMap<T, U> extends AbstractObservableWithUpstream<T, U> {
final Function<? super T, ? extends U> function;
public ObservableMap(ObservableSource<T> source, Function<? super T, ? extends U> function) {
super(source);
this.function = function;
}
可以看到其构造方法和刚才的 ObservableCreate 一样,将传入的对象进行了存储。不过可以发现这个类并不是继承自 Observable,而是 AbstractObservableWithUpstream,我们再跟进看看:
//AbstractObservableWithUpstream.java
abstract class AbstractObservableWithUpstream<T, U> extends Observable<U> implements HasUpstreamObservableSource<T> {
protected final ObservableSource<T> source;
AbstractObservableWithUpstream(ObservableSource<T> source) {
this.source = source;
}
@Override
public final ObservableSource<T> source() {
return source;
}
}
可以看到这个父类其实继承了 Observable,看到官方的注释可以知道,这个类是所有接受上一级输入的操作符(operator 如 map)的基类,这里的逻辑并不复杂,其实只是简单的封装了一下上一级的输入 source 和输出下一级的数据。分析之后可以看到,调用了 map 方法其实也是返回了一个 Observable 对象。
接着往下是 doOnNext(),看到这里可以猜测也是简单的返回一个 Observable 对象。不管怎么说,先进入源码看一看:
public final Observable<T> doOnNext(Consumer<? super T> onNext) {
return doOnEach(onNext, Functions.emptyConsumer(), Functions.EMPTY_ACTION, Functions.EMPTY_ACTION);
}
private Observable<T> doOnEach(Consumer<? super T> onNext, Consumer<? super Throwable> onError,
Action onComplete, Action onAfterTerminate) {
ObjectHelper.requireNonNull(onNext, "onNext is null");
ObjectHelper.requireNonNull(onError, "onError is null");
ObjectHelper.requireNonNull(onComplete, "onComplete is null");
ObjectHelper.requireNonNull(onAfterTerminate, "onAfterTerminate is null");
return RxJavaPlugins.onAssembly(new ObservableDoOnEach<T>(this, onNext, onError, onComplete, onAfterTerminate));
}
可以看到跳转到 doOnEach() 方法,传入的参数除了我们传进来的 Consumer 之外,其它都是传了空实现的 Consumer 对象。可以看到真的是简单的返回一个 Observable 对象。老规矩,先看一下 ObservableDoOnEach 的基础信息:
public final class ObservableDoOnEach<T> extends AbstractObservableWithUpstream<T, T> {
final Consumer<? super T> onNext;
final Consumer<? super Throwable> onError;
final Action onComplete;
final Action onAfterTerminate;
public ObservableDoOnEach(ObservableSource<T> source, Consumer<? super T> onNext,
Consumer<? super Throwable> onError,
Action onComplete,
Action onAfterTerminate) {
super(source);
this.onNext = onNext;
this.onError = onError;
this.onComplete = onComplete;
this.onAfterTerminate = onAfterTerminate;
}
同样的对所有信息进行了保存。可以看到这个类也是继承了 AbstractObservableWithUpstream,可以接受上一层的输入,并向下一层输出数据。
接着是线程调度(subscribeOn & observeOn),其实不看也猜得出这里也是直接返回对应的 Observable 对象。首先看一下 subscribeOn() :
public final Observable<T> subscribeOn(Scheduler scheduler) {
ObjectHelper.requireNonNull(scheduler, "scheduler is null");
return RxJavaPlugins.onAssembly(new ObservableSubscribeOn<T>(this, scheduler));
}
再看一下 ObserveOn() :
public final Observable<T> observeOn(Scheduler scheduler) {
return observeOn(scheduler, false, bufferSize());
}
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));
}
可以看到,这里分别返回了 ObservableSubscribeOn 和 ObservableObserveOn 对象,照旧我们看看这两个类的基础信息:
public final class ObservableSubscribeOn<T> extends AbstractObservableWithUpstream<T, T> {
final Scheduler scheduler;
public ObservableSubscribeOn(ObservableSource<T> source, Scheduler scheduler) {
super(source);
this.scheduler = scheduler;
}
一路看到这里,也能知道他这里的基础信息是什么了吧。再看看另外一个:
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;
}
同样的保存了传进去的基础信息,我们发现其中共同的都保存了 Scheduler 对象,我们先稍微看一下 Scheduler:
public abstract class Scheduler {
@NonNull
public abstract Worker createWorker();
@NonNull
public Disposable scheduleDirect(@NonNull Runnable run) {
return scheduleDirect(run, 0L, TimeUnit.NANOSECONDS);
}
public Disposable scheduleDirect(@NonNull Runnable run, long delay, @NonNull TimeUnit unit) {
final Worker w = createWorker();
w.schedule(new Runnable() {
@Override
public void run() {
try {
run.run();
} finally {
w.dispose();
}
}
}, delay, unit);
return w;
}
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 对外暴露了 scheduleDirect() 方法,这个方法通过调用抽象方法 createWorker 得到 worker 对象,然后调用 worker 对象的 schedule() 方法,执行 runnable。看到这里大致就能猜出 Scheduler 对应的逻辑啦,内部的 worker 对象维护自己的线程池,然后每次执行 schedule 方法时把 runnable 对象提交到线程池中。先这样理解,后面我们再深入一下。
接下来终于来到最后这个 subscribe() 方法了,前面全都是直接返回对象,难道所有逻辑都在最后实现吗?进去看一下先:
public final Disposable subscribe(Consumer<? super T> onNext, Consumer<? super Throwable> onError) {
return subscribe(onNext, onError, Functions.EMPTY_ACTION, Functions.emptyConsumer());
}
public final Disposable subscribe(Consumer<? super T> onNext, Consumer<? super Throwable> onError,
Action onComplete, Consumer<? super Disposable> onSubscribe) {
ObjectHelper.requireNonNull(onNext, "onNext is null");
ObjectHelper.requireNonNull(onError, "onError is null");
ObjectHelper.requireNonNull(onComplete, "onComplete is null");
ObjectHelper.requireNonNull(onSubscribe, "onSubscribe is null");
LambdaObserver<T> ls = new LambdaObserver<T>(onNext, onError, onComplete, onSubscribe);
subscribe(ls);
return ls;
}
public final void subscribe(Observer<? super T> observer) {
ObjectHelper.requireNonNull(observer, "observer is null");
try {
observer = RxJavaPlugins.onSubscribe(this, observer);
ObjectHelper.requireNonNull(observer, "Plugin returned null Observer");
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;
}
}
看着比较长,简化后代码是这样的:
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;
}
public final void subscribe(Observer<? super T> observer) {
subscribeActual(observer);
因为 subscribe() 的重载方法很多,这里只挑最终的两个,其中 LambdaObserver 其实就是把传进来的 Consumer 包装成一个 Observer,内部就是简单的在各个阶段调用我们传进去的 Consumer 的 accpet() 方法。接着就是直接调用了 subscribeActual() 方法。刚才我们在上述的步骤也说了,这个方法是 Observable 的抽象方法。
其实到这里我们可以看出,整个步骤通过对象的嵌套,形成了一条完整的链:
接着是逆向逐级订阅,按照我们刚才的案例,到最后subscribe() 方法的调用关系应该是这样的:
ObservableObserveOn.subscribe(LambdaObserver)
所以我们跟进看一下 ObservableObserveOn.subscribe() 方法的实现:
@Override
protected void subscribeActual(Observer<? super T> observer) {
//省略部分代码
Scheduler.Worker w = scheduler.createWorker();
source.subscribe(new ObserveOnObserver<T>(observer, w, delayError, bufferSize));
}
可以看到,这里通过 Scheduler 创建了一个 worker 对象,然后调用了 source(上一级) 的 subscribe() 方法,并通过已有的observer对象生成一个 ObserveOnObserver(注意是Observer)对象作为传参。看到这里也大概知道套路了,和刚才一样,会一直沿着整条链返回,一个一个订阅对应的 Observable 并生成新的嵌套的 Observer。我们依旧跟着看看,ObservableObserveOn.subscribe() 之后是 ObservableSubscribeOn.subscribe() :
@Override
public void subscribeActual(final Observer<? super T> s) {
//将上一级传进来的订阅者包装为线程安全的原子变量
//SubscribeOnObserver只是简单的包装,这里不展开
final SubscribeOnObserver<T> parent = new SubscribeOnObserver<T>(s);
//先在当前线程执行订阅者的onSubscribe方法
s.onSubscribe(parent);
//然后在指定的线程中执行source(上一级)的subscribe
parent.setDisposable(scheduler.scheduleDirect(new Runnable() {
@Override
public void run() {
source.subscribe(parent);
}
}));
}
根据我们最开始的业务逻辑,我们这里的 scheduler 应该对应 IO 线程,也就是说往下执行的 subscribe() 操作都是执行在 IO 线程中的。(现在是逆向遍历刚才建立的 observable 链)紧接着 ObservableDoOnEach.subscribe() :
@Override
public void subscribeActual(Observer<? super T> t) {
source.subscribe(new ObservableDoOnEach.DoOnEachObserver<T>(t, onNext, onError, onComplete, onAfterTerminate));
}
可以看到,这里也是封装了我们传进去的 Consumer 参数,直接调用了上一级的 source.subscribe() 方法。那么就接着往下看。应该来到了 ObservableMap.subscribe() 方法了。
@Override
public void subscribeActual(Observer<? super U> t) {
source.subscribe(new ObservableMap.MapObserver<T, U>(t, function));
}
可以看到也是封装了我们传进去的 Function 参数,然后调用上一级 source.subscribe() ,也就是 ObservableCreate.subscribe(),也就到了链的一开始。我们跟进看看ObservableCreate.subscribe():
@Override
protected void subscribeActual(Observer<? super T> observer) {
//首先是创建了CreateEmitter对象,这个类有没有觉得特别眼熟- -
ObservableCreate.CreateEmitter<T> parent = new ObservableCreate.CreateEmitter<T>(observer);
//然后调用了订阅者observer的onSubscribe方法
//这里的订阅者来自刚才的map操作
observer.onSubscribe(parent);
try {
//调用上一级source的subscribe方法
//显然没有上一级了,这里的source就是我们一开始创建的observer对象,调用的subscribe方法也就是我们调用的login()方法的地方
source.subscribe(parent);
} catch (Throwable ex) {
Exceptions.throwIfFatal(ex);
//捕获异常
parent.onError(ex);
}
}
终于回到了第一级,可以看到一样的封装了 observer 订阅者(这里的订阅者来自 map 操作),然后调用了 source.subscribe() 方法,看到这里不知道你们还记不记得 source 来自哪,看下面代码,这个 source 来自我们一开始调用 Observable.create() 时传进来的参数,而 subscribe() 方法就是我们一开始执行 login() 方法的地方:
Observable.create(new ObservableOnSubscribe<LoginApiResult>() {
@Override
public void subscribe(ObservableEmitter<LoginApiResult> e) throws Exception {
e.onNext(login());
}
}) //调用登录接口
……省略
也就是说,在刚才所有的逆序遍历过程中,下一级的 Observable 会生成的对应的 Observer 订阅上一级的source。
接下来就是激动人心的执行我们定义的任务链了。一趟创建,一趟逆向订阅,我们又回到了最开始的地方。我们刚才分析到,ObservableCreate 会执行我们定义的方法。所以就来到了这段代码:
public void subscribe(ObservableEmitter<LoginApiResult> e) throws Exception {
e.onNext(login());
}
就是调用 ObservableEmitter.onNext() 方法。我们跟进:
public final class ObservableCreate<T> extends Observable<T> {
protected void subscribeActual(Observer<? super T> observer) {
//可以看到,这里传入的Observer参数是来自下一级的订阅者
CreateEmitter<T> parent = new CreateEmitter<T>(observer);
//省略一堆- -
}
//省略继承关系
static final class CreateEmitter<T> {
//保存订阅者
CreateEmitter(Observer<? super T> observer) {
this.observer = observer;
}
@Override
public void onNext(T t) {
//省略判空
if (!isDisposed()) {
//调用订阅者的onNext方法
observer.onNext(t);
}
}
}
}
可以看到吧,简单的执行一些判断后,就调用了订阅者的 onNext() 方法,而通过上面的代码,我们可以看到 observer 来自于 subscribe 时调用构造函数的传参,而通过上述的分析,我们知道这里的订阅者来自下一级,也就是 map 操作生成的订阅者。这里很自然的进入了map操作。(后面不再贴出observer的来源)
我们再往下看到 MapObserver:
@Override
public void onNext(T t) {
//省略一些细节上的判断
U v;
//mapper就是我们new 的function对象
v = mapper.apply(t)
actual.onNext(v);
}
可以看到,这里调用了我们定义的 apply() 方法,获得了新的对象,然后调用了下一级订阅者的 onNext() 方法。看到这里大概就知道执行任务链的套路了。嵌套的调用下一级的 onNext() 方法。
我们先继续往下看,来到了 DoOnEachObserver 中:
@Override
public void onNext(T t) {
onNext.accept(t);
actual.onNext(t);
}
基本上和我们猜想的一样,accept() 方法就是我们定义的 doOnNext() 的操作。
再接着往下来到 SubscribeOnObserver:
@Override
public void onNext(T t) {
actual.onNext(t);
}
这货更直接,直接就调过去了。(这里涉及到Scheduler的线程调度,后面再补充)
快到重点了,再看一下 ObserveOnObserver:
@Override
public void onNext(T t) {
if (sourceMode != QueueDisposable.ASYNC) {
queue.offer(t);
}
schedule();
}
这货逻辑贼复杂,毕竟在这里进行了线程调度。暂时不深入。只需要知道:这货把任务提交给了 Scheduler 中的 worker。等到任务结束获取到结果后会调用下一级的 onNext() 方法。强行来到最后一层了,这里的 Observer 就是我们调用 subscribe 时传入的 Observer 啦。那就是调用:
@Override
public void accept(@NonNull UserInfoBean bean) throws Exception {LoginApiBean
//整个请求成功,根据获取的UserInfo更新对应的View
showSuccessView(bean);
}
行了,走完整个流程了。相信看到这里就能大致理解 Rx 的流程怎么走了。在刚才的遍历订阅后,每一步操作都会通知对应的 Observer,从而完成整调任务链。我这个画了一个详细的流程图便于大家理解:
总结一下步骤:
- 创建任务链,每一步都会返回对应的Observable对象。
- 逆向逐级订阅。每一步都会生成对应的Observer对上一步生成的Observable进行订阅
- 执行任务链。执行任务链之后,每一步都会通知对应的Observer,从而完成整调任务链。
四、线程切换
.subscribeOn(Schedulers.io()) //调度线程
.observeOn(AndroidSchedulers.mainThread()) //调度线程
我们知道,通过上述这两句代码,就使我们上半部分的请求和保存数据都执行在 io 线程中,而下半部的 ui 更新则执行在主线程。通过这段代码,我们引入几个问题:
- observeOn和subscribeOn是如何实现线程调度的?
- observeOn和subscribeOn之间是否存在冲突?
首先解决第一个问题,我们先了解一下 ObserveOn() 的实现原理,首先看一下调用:
public final Observable<T> observeOn(Scheduler scheduler) {
return observeOn(scheduler, false, bufferSize());
}
public final Observable<T> observeOn(Scheduler scheduler, boolean delayError, int bufferSize) {
return new ObservableObserveOn<T>(this, scheduler, delayError, bufferSize);
}
我们可以看到,ObserveOn() 最终是返回了一个 ObservableObserveOn 对象,并将 scheduler 传入。根据上一章的思路 ObservableObserveOn 会被我们最后 subscribe() 的时候传入的 Observer 订阅。让我们跟进看一下 ObservableObserveOn 被订阅时会执行什么逻辑:
@Override
protected void subscribeActual(Observer<? super T> observer) {
//TrampolineScheduler 表示当前线程
if (scheduler instanceof TrampolineScheduler) {
source.subscribe(observer);
} else {
//根据scheduler创建worker
Scheduler.Worker w = scheduler.createWorker();
//通过ObservableObserveOnObserver代理
source.subscribe(new ObservableObserveOn.ObserveOnObserver<T>(observer, w, delayError, bufferSize));
}
}
这里的逻辑并不难理解,首先是判断了 scheduler 是不是表示当前线程的 TrampolineScheduler,如果是就直接让 observer 订阅上一级的 Observable,也就是跳过当前这一层,即图中的 Observer 直接订阅 ObservableSubscribeOn。然后根据 schedular 生成对应的 worker,并交由 ObserveOnObserver 代理,订阅上一级的 Observable。
根据我们引入的案例,我们以 observeOn(AndroidSchedulers.mainThread()) 为例,当完成逆向订阅,执行任务链到ObserveOnObserver 时:
@Override
public void onNext(T t) {
// 上一级的模式如果不是异步的,加入队列
if (sourceMode != QueueDisposable.ASYNC) {
queue.offer(t);
}
//进行线程调度
schedule();
}
void schedule() {
// 判断当前正在执行的任务数目
if (getAndIncrement() == 0) {
worker.schedule(this);
}
}
首先是判断了 sourceMode,这里先不跟踪这个变量,只需要知道大多数情况下,这个判断是成立,所以会把数据加入队列。然后转而让 worker 执行接下去的步骤。我们跟踪看看,可以发现这是个抽象方法,可以找到他在不同类中有不同实现,分别对应了几种不同的线程调度机制,我们挑选案例中的 AndroidSchedulers.mainThread() 来跟踪。首先我们跟踪 mainThread() 方法,可以发现内部转到了这里:
static final Scheduler DEFAULT
= new HandlerScheduler(new Handler(Looper.getMainLooper()), false);
我们再跟进 HandlerScheduler,我们知道 worker 是通过 createWorker() 方法产生的:
public Worker createWorker() {
return new HandlerWorker(handler, async);
}
可以看到直接生成了 HandlerWorker,并传入了一开始创建的绑定了 MainLooper 的 Handler。看到这里也能大致猜出,后续会把任务传给这个 handler 执行:
@Override
public Disposable schedule(Runnable run, long delay, TimeUnit unit) {
//省略部分代码
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, Math.max(0L, unit.toMillis(delay)));
return scheduled;
}
可以看到这里将传进来的 runnable 包装成 ScheduledRunnable,然后提交给绑定的 handler。我们知道,后续 Handler 会调用 ScheduledRunnable 的 run() 方法:
ScheduledRunnable(Handler handler, Runnable delegate) {
this.handler = handler;
this.delegate = delegate;
}
@Override
public void run() {
try {
delegate.run();
} catch (Throwable t) {
//……
}
}
可以看到,只是简单的调用了我们传入的 runnable 的 run() 方法,也就是刚才我们在 ObserveOnObserver 中通过 schedule() 方法传入的 runnable,我们回去看看:
void schedule() {
// 判断当前正在执行的任务数目
if (getAndIncrement() == 0) {
worker.schedule(this);
}
}
可以看到其实本身就是个 runnable,我们看一下 ObserveOnObserver 的 run() 方法:
@Override
public void run() {
//输出结果是否融合
if (outputFused) {
drainFused();
} else {
drainNormal();
}
}
可以看到,根据 outputFused 来跳转方法,这里先不跟踪这个变量,后面会再提到。现在只需要知道当连续两个 observable 都需要线程调度时(比如从 observeOn 到 observeOn ),这个 outputFused 才会发生变化,默认为 false。那么这里,我们先进入 drainNormal() 方法:
void drainNormal() {
int missed = 1;
final SimpleQueue<T> q = queue;
final Observer<? super T> a = actual;
//第一层循环
for (;;) {
// 检查异常处理
if (checkTerminated(done, q.isEmpty(), a)) {
return;
}
//第二层循环
for (;;) {
boolean d = done;
T v;
//从队列中获取数据
v = q.poll();
boolean empty = v == null;
// 检查异常
if (checkTerminated(d, empty, a)) {
return;
}
//如果没有数据了,跳出
if (empty) {
break;
}
//执行下一次操作。
a.onNext(v);
}
//减掉执行的次数,并获取剩余任务数量,然后再次循环
//直到获取剩余任务量为0,跳出循环
missed = addAndGet(-missed);
if (missed == 0) {
break;
}
}
}
这里的逻辑其实也不难,具体可以看注释。到这里其实已经切换了线程,然后就是分发数据,逐个调用onNext() 操作了。直到没有数据就跳出循环。(总觉得这里missed的设计很奇怪- -为什么是初始化1而不是missed=get()呢。望有大神解答~)
看到这里也就大致明白了 ObserveOn() 的流程了。总结一下:ObserveOn 会用一个 queue 保存上一级传下来的数据,然后通过 scheduler 创建一个 worker,提交数据,并将任务执行在 worker 设置的线程中。
看完 ObserveOn,我们看一下 subscribeOn(),首先看一下当它被订阅时会执行什么操作:
//ObservableSubscribeOn.java
@Override
public void subscribeActual(final Observer<? super T> s) {
//创建对应的Observer
final SubscribeOnObserver<T> parent = new SubscribeOnObserver<T>(s);
//执行线程调度,内部会订阅上一级的Observable
parent.setDisposable(scheduler.scheduleDirect(new SubscribeTask(parent)));
}
可以看到这里直接进行了线程调度,创建了 SubscribeTask 任务,然后交由 Scheduler 执行。我们先看看 scheduleDirect() 会执行什么操作:
@NonNull
public Disposable scheduleDirect(@NonNull Runnable run, long delay, @NonNull TimeUnit unit) {
final Scheduler.Worker w = createWorker();
Scheduler.DisposeTask task = new Scheduler.DisposeTask(run, w);
w.schedule(task, delay, unit);
return task;
}
可以看到这里和我们刚才追踪 ObserveOn() 时的逻辑一样,都是将任务交给了 Worker 处理。我们刚才已经分析了,Worker 会将任务提交给对应的线程执行。所以我们回过头看一下我们提交了什么任务:
@Override
public void run() {
source.subscribe(parent);
}
可以看出,这里将订阅的操作提交给了 Worker 执行。总结一下:subscribeOn() 会将订阅上一级的操作调交给 worker 中对应的线程执行。
总结
我们还是以上述引入的例子为例,可以看出,整个过程进行了两次线程调度,首先是 subscribeOn(),然后是ObserveOn(),这个过程比较简单,先解析这个过程。根据上一篇文章的分析,RxJava的整个流程分为三个步骤:
- 创建任务链,这里没有涉及线程调度。默认执行在当前线程,在这里也就是主线程。
- 逆向订阅,这里当遇到 ObserveOn() 的时候,ObserveOn() 直接进行了订阅操作,所以没有影响。但是但我们订阅 ObservableSubscribeOn 的时候,其便将订阅操作提交到了对应线程,所以后续的订阅操作都执行在对应线程,在这里便是 IO 线程。
- 执行任务链,受到 ObservableSubscribeOn 的影响,这里也会继续执行在 IO 线程。但是当我们执行到 ObserveOnObserver 的时候,onNext() 操作会执行在对应的线程中,在这里也就是切换到主线程。