一、从比较简单的Single入手,一步步分析总结
下面是一段基于RxJava3的简单任务创建&Map操作符示例
Single.just(1)
.subscribeOn(Schedulers.io())
.map(object:Function<Int,String>{
override fun apply(t: Int?): String {
Thread.sleep(2000)
return t.toString()
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object:SingleObserver<String>{
override fun onSuccess(t: String?) {
}
override fun onSubscribe(d: Disposable?) {
}
override fun onError(e: Throwable?) {
}
})
在io线程睡2s再将数字转换为String返回,并在ui主线程收到这个string值。为了方便阅读 就不做lambda简化了。
二、首先,为什么这代码如此“流式”?
因为从just开始一直到observeOn这四个方法返回的都是 Single 有一点点像Builder模式的感觉,只是感觉哈,就是能一直...,如果不这么玩有其他办法?有的,比如使用地狱回调嵌套。
这里需要提一下:Rxjava是采用了响应式编程的思想[采用生产者/消费者模型]同时提供良好API调用体验的一个封装库,或者叫线程工具。
三、线程切换怎么切换的
因为已经分析过有理解,就不记录那些绕弯子的过程了。直接从最下面往上读源码,并用最直白的易懂的逻辑描述出来,毕竟说不出来的知识是“假知识”。
- 1 subscribe方法,这方法传递进去了一个SingleObserver,用于接受回调通知。 追这个方法,一直追会看到实际内部是调用 subscribeActual方法,这个方法也是Single的哦,因为上面每个操作都返回的Single嘛。
public final void subscribe(@NonNull SingleObserver<? super T> observer) {
...
try {
subscribeActual(observer);
...
}
}
- 2 接着看创建这个observer的方法的observeOn方法,注意外面传递进去了一个mainThread调度器,这个很关键,一定要记住此时传进去的。
public final Single<T> observeOn(@NonNull Scheduler scheduler) {
Objects.requireNonNull(scheduler, "scheduler is null");
return RxJavaPlugins.onAssembly(new SingleObserveOn<>(this, scheduler));
}
可以看到创建了SingleObserveOn返回,并且传递进去了this,和scheduler。这里又要敲黑板了,this是谁?scheduler是谁? this就是调用这个方法对象,就是上一个方法的返回对象即map的。 scheduler呢,就是mainThread。 看一下mainThread是个什么,
public final class AndroidSchedulers {
private static final class MainHolder {
static final Scheduler DEFAULT
= new HandlerScheduler(new Handler(Looper.getMainLooper()), true);
}
private static final Scheduler MAIN_THREAD =
RxAndroidPlugins.initMainThreadScheduler(() -> MainHolder.DEFAULT);
public static Scheduler mainThread() {
return RxAndroidPlugins.onMainThreadScheduler(MAIN_THREAD);
}
...
哦创建了一个封装的HandlerScheduler传递进去了一个由MainLooper 构建的Handler,啊好像明白了什么又说不出来。先不急等会儿再过来看,因为还没到他执行 这里只要知道他是个什么类型,方便一会儿找到他。
- 3 回到上面执行位置,继续看 observeOn()接受this与scheduler的对象 SingleObserveOn 关注点当然是subscribeActual方法啦,因为上面分析过,每个Single订阅执行的都是这个方法。 SingleObserveOn 的SingleObserveOn方法
public final class SingleObserveOn<T> extends Single<T> {
final SingleSource<T> source;
final Scheduler scheduler;
public SingleObserveOn(SingleSource<T> source, Scheduler scheduler) {
this.source = source;
this.scheduler = scheduler;
}
@Override
protected void subscribeActual(final SingleObserver<? super T> observer) {
source.subscribe(new ObserveOnSingleObserver<>(observer, scheduler));
}
...先省略
这里也很关键哦,source就是上游Single对象,就是前面敲黑板记的this。 可以看到这里创建了一个内部的observer,并订阅给上游用于接收上游的回调。 而此时在SingleObserveOn中的subscribeActual接收的SingleObserver 是谁呢?就是它嘛subscribe(object:SingleObserver{}就是开发者关注的最终观察者。可以看到这里将下游观察者传递给了内部观察者。
- 4 既然是内部创建新的观察者订阅给上游,那这个内部观察者肯定会在上游回调后执行。也就是接收上游的参数传递后执行自己的逻辑。那这里可以先不看上游,就先看他自己是如何回调给自己的下游的。好绕啊,好多游啊 !长代码警告!
static final class ObserveOnSingleObserver<T> extends AtomicReference<Disposable>
implements SingleObserver<T>, Disposable, Runnable {
private static final long serialVersionUID = 3528003840217436037L;
final SingleObserver<? super T> downstream;
final Scheduler scheduler;
T value;
Throwable error;
ObserveOnSingleObserver(SingleObserver<? super T> actual, Scheduler scheduler) {
this.downstream = actual;
this.scheduler = scheduler;
}
@Override
public void onSubscribe(Disposable d) {
if (DisposableHelper.setOnce(this, d)) {
downstream.onSubscribe(this);
}
}
@Override
public void onSuccess(T value) {
this.value = value;
Disposable d = scheduler.scheduleDirect(this);
DisposableHelper.replace(this, d);
}
@Override
public void onError(Throwable e) {
this.error = e;
Disposable d = scheduler.scheduleDirect(this);
DisposableHelper.replace(this, d);
}
@Override
public void run() {
Throwable ex = error;
if (ex != null) {
downstream.onError(ex);
} else {
downstream.onSuccess(value);
}
}
...
}
重写敲黑板,此时逻辑还在observeOn中哦!! ObserveOnSingleObserver接受两个构造参数,actual 下游的观察者 并赋值给downstream 这名字多好啊,下游!scheduler 外部类的scheduler,也就是mainThread,也就是那个HandlerScheduler。 ObserveOnSingleObserver实现了runnable接口,在run方法中调用下游观察者对象 downstream的onError,onSuccess。那下面就找找这个run方法被那个家伙执行的吧。 既然这个内部类接管了上游的回调,由在run方法执行时传递给下游,那在上游回调时肯定得干点什么吧
@Override
public void onSuccess(T value) {
this.value = value;
Disposable d = scheduler.scheduleDirect(this);
DisposableHelper.replace(this, d);
}
@Override
public void onError(Throwable e) {
this.error = e;
Disposable d = scheduler.scheduleDirect(this);
DisposableHelper.replace(this, d);
}
直击scheduler.scheduleDirect(this),那也就是HandlerScheduler的scheduleDirect方法,追!
public Disposable scheduleDirect(Runnable run, long delay, TimeUnit unit) {
...
ScheduledRunnable scheduled = new ScheduledRunnable(handler, run);
Message message = Message.obtain(handler, scheduled);
if (async) {
message.setAsynchronous(true);
}
handler.sendMessageDelayed(message, unit.toMillis(delay));
return scheduled;
}
这里代码比较好读了,创建内部ScheduledRunnable对象包装外部的Runnable对象,在run方法中调用外部run方法。使用mainLooper构建的handler发送这条消息。那到目前位置,在示例代码中最后两个方法就分析完了。
结论:在ObserveOn指定的线程决定了紧挨着的订阅者接收线程,内部通过将收到的上游回调参数,用主线程handler切换线程后传递给下游,完成线程切换。也就是ObserveOn影响的是下游的接收线程。
也就是说最后设置的观察者上必须紧紧挨着ObserveOn?就目前分析的结果是这样,但是事实并不是这么简单。 这一个疑问先放一放,接着看map吧
- 5 map操作符的内部与上下游关系 map方法内部创建SingleMap,也就收一个上游this,还有一个函数对象mapper。很好理解,mapper就是外部创的function嘛,实现了apply方法。
public final class SingleMap<T, R> extends Single<R> {
final SingleSource<? extends T> source;
final Function<? super T, ? extends R> mapper;
public SingleMap(SingleSource<? extends T> source, Function<? super T, ? extends R> mapper) {
this.source = source;
this.mapper = mapper;
}
@Override
protected void subscribeActual(final SingleObserver<? super R> t) {
source.subscribe(new MapSingleObserver<T, R>(t, mapper));
}
...
这里跟前面的差不多,在subscribeActual方法中创建内部观察者订阅给上游,并保存了下游观察者与mapper函数。 重点看一下它的ouSuccess方法
@Override
public void onSuccess(T value) {
R v;
try {
v = Objects.requireNonNull(mapper.apply(value), "The mapper function returned a null value.");
...
t.onSuccess(v);
}
这就很清楚了,接收上游的value,并调用mapper.apply进行转换,再调用下游的观察者的onSuccess传递。这也就是为什么map操作符之后订阅的onSuccess类型需要与apply方法的返回值类型相同了。 除此之外,这里也没有切换线程,也就是说上游回调时在什么线程,那当前就在什么线程。 总结:在此例子中,操作符的执行线程取决于其上游指定的线程。
- 6 最后来看subscribeOn方法吧
Single.just(1)就没必要记录了,因为他很简单的创建模式,在subscribeActual 中往下游的onSuccess传递1这个值。
subscribeOn内部创建SingleSubscribeOn对象,并接受上游this,与io scheduler 这个调度器。 有过前面的经验这里也直接看subscribeActual
@Override
protected void subscribeActual(final SingleObserver<? super T> observer) {
final SubscribeOnObserver<T> parent = new SubscribeOnObserver<>(observer, source);
observer.onSubscribe(parent);
Disposable f = scheduler.scheduleDirect(parent);
parent.task.replace(f);
}
哦~又看到了scheduleDirect。不过这里是io调度器的实现了。SubscribeOnObserver也实现了Runnable接口,并在run方法中将自己订阅给上游,又在onSuccess中直接传递给下游。
static final class SubscribeOnObserver<T>
extends AtomicReference<Disposable>
implements SingleObserver<T>, Disposable, Runnable {
final SingleObserver<? super T> downstream;
final SequentialDisposable task;
final SingleSource<? extends T> source;
SubscribeOnObserver(SingleObserver<? super T> actual, SingleSource<? extends T> source) {
this.downstream = actual;
this.source = source;
this.task = new SequentialDisposable();
}
@Override
public void onSuccess(T value) {
downstream.onSuccess(value);
}
@Override
public void run() {
source.subscribe(this);
}
...省略
}
上游是谁呢?Single.Just 他并没有指定线程,但是订阅他的时候他才开始执行,订阅线程也就意味着他的执行线程,也意味着是下游onSuccess的接收线程。那不就是这里run方法执行的线程嘛。
- io scheduler 的 scheduleDirect方法 不卖关子了 就是IoScheduler,但是并没有 scheduleDirect方法,那就向上找吧 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();
final Runnable decoratedRun = RxJavaPlugins.onSchedule(run);
DisposeTask task = new DisposeTask(decoratedRun, w);
w.schedule(task, delay, unit);
return task;
}
看最后,w.schedule 执行了任务。不要忘记了这里的createWorker,与schedule都是IoScheduler的方法哦。拐回去看吧
@NonNull
@Override
public Worker createWorker() {
return new EventLoopWorker(pool.get());
}
static final class EventLoopWorker extends Scheduler.Worker {
...省略
private final ThreadWorker threadWorker;
final AtomicBoolean once = new AtomicBoolean();
EventLoopWorker(CachedWorkerPool pool) {
this.pool = pool;
this.tasks = new CompositeDisposable();
this.threadWorker = pool.get();
}
@NonNull
@Override
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);
}
}
最终调用到threadWorker.scheduleActual,继续追! 不卖关子直接追到NewThreadWorker
@NonNull
public ScheduledRunnable scheduleActual(final Runnable run, long delayTime, @NonNull TimeUnit unit, @Nullable DisposableContainer parent) {
...省略
try {
if (delayTime <= 0) {
f = executor.submit((Callable<Object>)sr);
} else {
f = executor.schedule((Callable<Object>)sr, delayTime, unit);
}
...
return sr;
}
啊executor.submit,executor.schedule熟啊这不是java的线程池api嘛。这里也不用贴代码了,确实是一个核心数为1,非核心线程5-10个的线程池。 到这里也就完成了在后台线程执行上游任务,并且下游默认也是在后台线程接收的逻辑分析。
总结:到此observeOn,与subscribeOn就分析完了,从源码可以看出
- observeOn是在接收到上游通知后 再切换线程 通知给下游,决定着下游收到通知的线程,如果有多个下游则可以多次切换下游获取通知的线程
- subscribeOn 是在切换成线程后进行订阅,也就是指定发射线程,也就是指定上游的执行线程,因为是自下儿上的订阅上游,多次使用subscribeOn最终就会切换到到第一次subscribeOn指定的线程,也就是会造成只有第一次设置生效的假象,实际上每一层的线程切换都会执行,只是又浪费又没用。
舒坦~~ 额。。上面还有个问题没搞清楚呢,舒坦什么呀。现在已经1点1刻了。先休息吧,明日再续。
隔日补充 - -!
四、最终订阅的观察者线程到底属于谁调度的线程?
根据上面的理解不难总结: 调用subscribe(Observer)设置的Observer的接收线程在哪里?在离他最近的ObserverOn指定的线程,如果没有呢,就是在第一次指定subscribeOn指定的线程,都没有呢?原始线程。 基于map操作符的测试代码
Single.just(1)
.observeOn(Schedulers.io())
.subscribeOn(AndroidSchedulers.mainThread())
.map(object:Function<Int,Int>{
override fun apply(t: Int): Int {
println("run2 map 1 线程:${Thread.currentThread().name}")
return t+1
}
})
.map(object:Function<Int,Int>{
override fun apply(t: Int): Int {
println("run2 map 2 线程:${Thread.currentThread().name}")
return t+1
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object:SingleObserver<Int>{
override fun onSubscribe(d: Disposable?) {
println("run2 onSubscribe 线程:${Thread.currentThread().name}")
}
override fun onSuccess(t: Int?) {
println("run2 onSuccess 线程:${Thread.currentThread().name}")
}
override fun onError(e: Throwable?) {
}
})
本篇仅以最简单的创建类型进行分析,分析明白流式+线程调度的本质。至于其他复杂操作符引申的变化此处不做展开。