一、前言
上一篇文章:【Rxjava2源码系列】基本订阅、消耗事件流程(一)
已经弄清楚了Rxjava的整体流程,本文就来看看Rxjava强大的线程转换能力。
相信大家最常用到Rxjava的地方就是利用Retrofit做网络请求了吧?不仅如此,只要有耗时操作,都可以考虑利用Rxjava来实现,就是这么任性。本文要研究的包括
1、线程调度如何实现?
2、subscribeOn、observeOn有什么区别
二、subscribeOn、observeOn
一般,我们使用subscribeOn和observeOn来切换线程,我们首先来看看subscribeOn,打开它的源码发现和我们以前分析的map、create之类的方法一样,最终走到了subscribeActual,具体流程上一篇文章已经分析过了,这里我仅贴上代码,方便大家查看
@SchedulerSupport(SchedulerSupport.CUSTOM)
public final Observable<T> subscribeOn(Scheduler scheduler) {
ObjectHelper.requireNonNull(scheduler, "scheduler is null");
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> s) {
final SubscribeOnObserver<T> parent = new SubscribeOnObserver<T>(s);
s.onSubscribe(parent);
parent.setDisposable(scheduler.scheduleDirect(new Runnable() {
@Override
public void run() {
//线程转换后进行subscribe操作
source.subscribe(parent);
}
}));
}
}
可以看见,ObservableSubscribeOn里同样有自己的observer:SubscribeOnObserver,这里我们不管,直接看最重要的一句:scheduler.scheduleDirect
,调用了scheduler的方法,传入了一个runnable,跟进去看看
public Disposable scheduleDirect(Runnable run) {
return scheduleDirect(run, 0L, TimeUnit.NANOSECONDS);
}
public Disposable scheduleDirect(Runnable run, long delay, TimeUnit unit) {
//调用createWorker返回一个worker
final Worker w = createWorker();
//RxJavaPlugins的hook操作,暂时无视
final Runnable decoratedRun = RxJavaPlugins.onSchedule(run);
//调用work的schedule方法传入一个runnable对象
w.schedule(new Runnable() {
@Override
public void run() {
try {
//手动调用了run方法
decoratedRun.run();
} finally {
w.dispose();
}
}
}, delay, unit);
return w;
}
//Scheduler类的抽象方法,在子类中实现
public abstract Worker createWorker();
这里调用createWorker返回了一个worker,createWorker是一个抽象方法由子类实现,想必就是IO、Main等scheduler去实现的。接下来就调用了worker的schedule方法传入一个runnable,就是这里做的异步操作了,由子类控制是在哪个线程操作,值得注意的是刚刚传入的runnable并没有start,而是直接调用的run方法。
由此可知后面执行的observable的subscribe方法就会调用在此线程中,完成了线程的切换。
具体等会再详细讨论如何进行的异步,我们先来看看observeOn方法,同样在一系列调用之后到了subscribeActual方法里。
@Override
protected void subscribeActual(Observer<? super T> observer) {
if (scheduler instanceof TrampolineScheduler) {
//TrampolineScheduler直接在当前线程中执行,无需转换线程
source.subscribe(observer);
} else {
//直接调用createWorker返回worker
Scheduler.Worker w = scheduler.createWorker();
//将操作转到ObserveOnObserver中
source.subscribe(new ObserveOnObserver<T>(observer, w, delayError, bufferSize));
}
}
接着看ObserveOnObserver实现
static final class ObserveOnObserver<T> extends BasicIntQueueDisposable<T>
implements Observer<T>, Runnable {
//省略成员、构造函数、onSubscribe等
@Override
public void onNext(T t) {
if (done) {
return;
}
if (sourceMode != QueueDisposable.ASYNC) {
queue.offer(t);
}
schedule();
}
//省略error等方法
void schedule() {
if (getAndIncrement() == 0) {
worker.schedule(this);
}
}
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;
try {
v = q.poll();
} catch (Throwable ex) {
Exceptions.throwIfFatal(ex);
s.dispose();
q.clear();
a.onError(ex);
return;
}
boolean empty = v == null;
if (checkTerminated(d, empty, a)) {
return;
}
if (empty) {
break;
}
a.onNext(v);
}
missed = addAndGet(-missed);
if (missed == 0) {
break;
}
}
}
void drainFused() {
int missed = 1;
for (;;) {
if (cancelled) {
return;
}
boolean d = done;
Throwable ex = error;
if (!delayError && d && ex != null) {
actual.onError(error);
worker.dispose();
return;
}
actual.onNext(null);
if (d) {
ex = error;
if (ex != null) {
actual.onError(ex);
} else {
actual.onComplete();
}
worker.dispose();
return;
}
missed = addAndGet(-missed);
if (missed == 0) {
break;
}
}
}
@Override
public void run() {
if (outputFused) {
drainFused();
} else {
drainNormal();
}
}
}
可以看见ObserveOnObserver实现了runnable,当执行到onNext时,就会调用worker的schedule方法,这里和subscribeOn一样进行了异步调用。由于传入的是This,所以会执行run方法,经过一系列判断依然会调用onNext方法。
此时已经进行过线程转换,所以下游的observer的onNext也会执行在此线程了。
三、scheduler
搞清楚了线程如何切换,接下来继续看看异步操作是如何产生的,刚刚我说是worker的schedule方法产生的异步,而worker又是子类createWorker方法生成的,所以我们直接去看子类的该方法。
一般我们线程转换会调用如下代码:
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
先来看看Schedulers.io(),他返回的是一个IoScheduler类,看看他的createWorker
@Override
public Worker createWorker() {
return new EventLoopWorker(pool.get());
}
返回了一个EventLoopWorker,参数是CachedWorkerPool,看名字就知道是任务缓存池了,由于不是我们的重点就不过多讲解了,我们来看看这个worker
static final class EventLoopWorker extends Scheduler.Worker {
private final CompositeDisposable tasks;
private final CachedWorkerPool pool;
private final ThreadWorker threadWorker;
final AtomicBoolean once = new AtomicBoolean();
EventLoopWorker(CachedWorkerPool pool) {
this.pool = pool;
this.tasks = new CompositeDisposable();
this.threadWorker = pool.get();
}
//.....
@Override
public Disposable schedule(Runnable action, long delayTime, TimeUnit unit) {
if (tasks.isDisposed()) {
// don't schedule, we are unsubscribed
return EmptyDisposable.INSTANCE;
}
return threadWorker.scheduleActual(action, delayTime, unit, tasks);
}
}
我们可以看到schedule方法其实是调用了threadWorker的scheduleActual方法。而threadWorker是一个ThreadWorker 实例,ThreadWorker 继承于NewThreadWorker,scheduleActual方法就实现在里面了
public ScheduledRunnable scheduleActual(final Runnable run, long delayTime, TimeUnit unit, DisposableContainer parent) {
//RxJavaPlugins钩子,暂时无视...
Runnable decoratedRun = RxJavaPlugins.onSchedule(run);
//封装了传入的runnable,可以当做Future进行任务管理
ScheduledRunnable sr = new ScheduledRunnable(decoratedRun, parent);
//存入container容器中
if (parent != null) {
if (!parent.add(sr)) {
return sr;
}
}
//可以管理任务
Future<?> f;
try {
//利用线程池执行任务
if (delayTime <= 0) {
f = executor.submit((Callable<Object>)sr);
} else {
f = executor.schedule((Callable<Object>)sr, delayTime, unit);
}
sr.setFuture(f);
} catch (RejectedExecutionException ex) {
parent.remove(sr);
RxJavaPlugins.onError(ex);
}
return sr;
}
好了,到这里已经很清晰了,是利用线程池执行了任务,实现了线程转换。
接下来我们看看AndroidSchedulers.mainThread(),他返回的是HandlerScheduler对象,看名字就很熟悉啦~依旧看看他的createWorker方法
@Override
public Worker createWorker() {
return new HandlerWorker(handler);
}
继续跟进HandlerWorker
private static final class HandlerWorker extends Worker {
private final Handler handler;
private volatile boolean disposed;
HandlerWorker(Handler handler) {
this.handler = handler;
}
@Override
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");
if (disposed) {
return Disposables.disposed();
}
run = RxJavaPlugins.onSchedule(run);
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)));
// Re-check disposed state for removing in case we were racing a call to dispose().
if (disposed) {
handler.removeCallbacks(scheduled);
return Disposables.disposed();
}
return scheduled;
}
//......
}
也很简单,就是利用handler转换线程啦!而这个handler是在构造时传入的,也就是这里:
static final Scheduler DEFAULT = new HandlerScheduler(new Handler(Looper.getMainLooper()));
OK,获取的是main线程的looper,也就是可以转换到主线程了。
四、subscribeOn、observeOn区别
这个问题可能是很多Rxjava使用者的共同话题,笔者也很长一段时间没有弄清楚。仔细的读者可能已经发现我之前特意加粗的两行字,这里再放出来对比一下:
subscribeOn:由此可知后面执行的observable的subscribe方法就会调用在此线程中,完成了线程的切换。
observeOn:此时已经进行过线程转换,所以下游的observer的onNext也会执行在此线程了。
阅读过我的上一篇文章的读者也许已经明白的他们之间的差别,没错,一个是subscribe方法异步,而另一个是onNext(系列)方法异步,为了能更好理解,我就再整个梳理一遍。下面列出比较简单的一个线程转换示例:
Observable.create(new ObservableOnSubscribe<String>() {
@Override
public void subscribe(ObservableEmitter<String> e) throws Exception {
e.onNext("1");
e.onComplete();
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.map(new Function<String, String>() {
@Override
public String apply(String s) throws Exception {
return "_"+s;
}
})
.subscribe(new Observer<String>() {
@Override
public void onSubscribe(Disposable d) {
Log.d(TAG, "onSubscribe() called with: d = [" + d + "]");
}
@Override
public void onNext(String value) {
Log.d(TAG, "onNext() called with: value = [" + value + "]");
}
@Override
public void onError(Throwable e) {
Log.d(TAG, "onError() called with: e = [" + e + "]");
}
@Override
public void onComplete() {
Log.d(TAG, "onComplete() called");
}
});
转换为图片之后:
好了,梳理完了(斜眼笑),没有逗你,精华就是这张图了,PS:图中横向箭头指的是持有,执行顺序大多是纵向箭头
看图说话:
1、无论subscribeOn调用多少次,真正起作用的也就只有最靠近我们创建Observable的那个有效(也就是网上大多数的说法:第一次调用有效)
2、observeOn只会影响下游的observable,可以多次生效
OK,线程调度就讲解完了,期待下一篇吧^ ^。