RxJava2 源码分析
前言
很多项目使用流行的Rxjava2 + Retrofit搭建网络框架,Rxjava现在已经发展到Rxjava2,之前一直都只是再用Rxjava,但从来没有了解下Rxjava的内部实现,接下来一步步来分析Rxjava2的源码,Rxjava2分Observable和Flowable两种(无被压和有被压),我们今天先从简单的无背压的observable来分析。源码基于rxjava:2.1.1。
一、Rxjava如何创建事件源、发射事件、何时发射事件、如何将观察者和被观察者关联起来
简单的例子
先来段最简单的代码,直观的了解下整个Rxjava运行的完整流程。
private void doSomeWork() {
Observable<String> observable = Observable.create(new ObservableOnSubscribe<String>() {
@Override
public void subscribe(ObservableEmitter<String> e) throws Exception {
e.onNext("a");
e.onComplete();
}
});
Observer observer = new Observer<String>() { @Override
public void onSubscribe(Disposable d) {
Log.i("lx", " onSubscribe : " + d.isDisposed());
} @Override
public void onNext(String str) {
Log.i("lx", " onNext : " + str);
} @Override
public void onError(Throwable e) {
Log.i("lx", " onError : " + e.getMessage());
} @Override
public void onComplete() {
Log.i("lx", " onComplete");
}
};
observable.subscribe(observer);
}
上面代码之所以将observable和observer单独声明,最后再调用observable.subscribe(observer);
是为了分步来分析:
- 被观察者 Observable 如何生产事件的
- 被观察者 Observable 何时生产事件的
- 观察者Observer是何时接收到上游事件的
- Observable 与Observer是如何关联在一起的
Observable
Observable是数据的上游,即事件生产者
首先来分析事件是如何生成的,直接看代码 Observable.create()
方法。
@SchedulerSupport(SchedulerSupport.NONE)
public static <T> Observable<T> create(ObservableOnSubscribe<T> source) { // ObservableOnSubscribe 是个接口,只包含subscribe方法,是事件生产的源头。
ObjectHelper.requireNonNull(source, "source is null"); // 判空
return RxJavaPlugins.onAssembly(new ObservableCreate<T>(source));
}
最重要的是RxJavaPlugins.onAssembly(new ObservableCreate<T>(source));这句代码。继续跟踪进去
/**
* Calls the associated hook function.
* @param <T> the value type
* @param source the hook's input value
* @return the value returned by the hook
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
@NonNull
public static <T> Observable<T> onAssembly(@NonNull Observable<T> source) {
Function<? super Observable, ? extends Observable> f = onObservableAssembly;
if (f != null) {
return apply(f, source);
}
return source;
}
看注释,原来这个方法是个hook function。 通过调试得知静态对象onObservableAssembly默认为null, 所以此方法直接返回传入的参数source。
onObservableAssembly可以通过静态方法RxJavaPlugins. setOnObservableAssembly ()设置全局的Hook函数, 有兴趣的同学可以自己去试试。 这里暂且不谈,我们继续返回代码。
现在我们明白了:
Observable<String> observable=Observable.create(new ObservableOnSubscribe<String>() {
...
...
})
相当于:
Observable<String> observable=new ObservableCreate(new ObservableOnSubscribe<String>() {
...
...
}))
好了,至此我们明白了,事件的源就是new ObservableCreate()
对象,将ObservableOnSubscribe
作为参数传递给ObservableCreate
的构造函数。
事件是由接口ObservableOnSubscribe
的subscribe方法上产的,至于何时生产事件,稍后再分析。
Observer
Observer 是数据的下游,即事件消费者
Observer是个interface,包含 :
void onSubscribe(@NonNull Disposable d);
void onNext(@NonNull T t);
void onError(@NonNull Throwable e);
void onComplete();
上游发送的事件就是再这几个方法中被消费的。上游何时发送事件、如何发送,稍后再表。
subscribe
重点来了,接下来最重要的方法来了:observable.subscribe(observer);
从这个方法的名字就知道,subscribe是订阅,是将观察者(observer)与被观察者(observable)连接起来的方法。只有subscribe方法执行后,上游产生的事件才能被下游接收并处理。其实自然的方式应该是observer订阅(subscribe) observable, 但这样会打断rxjava的链式结构。所以采用相反的方式。
接下来看源码,只列出关键代码
public final void subscribe(Observer<? super T> observer) {
ObjectHelper.requireNonNull(observer, "observer is null");
......
observer = RxJavaPlugins.onSubscribe(this, observer); // hook ,默认直接返回observer
......
subscribeActual(observer); // 这个才是真正实现订阅的方法。
......
} // subscribeActual 是抽象方法,所以需要到实现类中去看具体实现,也就是说实现是在上文中提到的ObservableCreate中
protected abstract void subscribeActual(Observer<? super T> observer);
接下来我们来看ObservableCreate.java:
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); //直接回调了观察者的onSubscribe try {
// 调用了事件源subscribe方法生产事件,同时将发射器传给事件源。
// 现在我们明白了,数据源生产事件的subscribe方法只有在observable.subscribe(observer)被执行
后才执行的。 换言之,事件流是在订阅后才产生的。
//而observable被创建出来时并不生产事件,同时也不发射事件。
source.subscribe(parent);
} catch (Throwable ex) {
Exceptions.throwIfFatal(ex);
parent.onError(ex);
}
}
现在我们明白了,数据源生产事件的subscribe方法只有在observable.subscribe(observer)被执行后才执行的。 换言之,事件流是在订阅后才产生的。而observable被创建出来时并不生产事件,同时也不发射事件。
接下来我们再来看看事件是如何被发射出去,同时observer是如何接收到发射的事件的
CreateEmitter<T> parent = new CreateEmitter<T>(observer);
CreateEmitter 实现了ObservableEmitter接口,同时ObservableEmitter接口又继承了Emitter接口。
CreateEmitter 还实现了Disposable接口,这个disposable接口是用来判断是否中断事件发射的。
从名称上就能看出,这个是发射器,故名思议是用来发射事件的,正是它将上游产生的事件发射到下游的。
Emitter是事件源与下游的桥梁。
CreateEmitter 主要包括方法:
void onNext(@NonNull T value);
void onError(@NonNull Throwable error);
void onComplete();
public void dispose() ;
public boolean isDisposed();
是不是跟observer的方法很像?
我们来看看CreateEmitter中这几个方法的具体实现:
只列出关键代码
public void onNext(T t) {
if (!isDisposed()) { // 判断事件是否需要被丢弃
observer.onNext(t); // 调用Emitter的onNext,它会直接调用observer的onNext
}
}
public void onError(Throwable t) {
if (!isDisposed()) {
try {
observer.onError(t); // 调用Emitter的onError,它会直接调用observer的onError
} finally {
dispose(); // 当onError被触发时,执行dispose(), 后续onNext,onError, onComplete就不会继
续发射事件了
}
}
} @Override
public void onComplete() {
if (!isDisposed()) {
try {
observer.onComplete(); // 调用Emitter的onComplete,它会直接调用observer的onComplete
} finally {
dispose(); // 当onComplete被触发时,也会执行dispose(), 后续onNext,onError, onComplete
同样不会继续发射事件了
}
}
}
CreateEmitter 的onError和onComplete方法任何一个执行完都会执行dispose()中断事件发射,所以observer中的onError和onComplete也只能有一个被执行。
现在终于明白了,事件是如何被发射给下游的。当订阅成功后,数据源ObservableOnSubscribe开始生产事件,调用Emitter的onNext,onComplete向下游发射事件,
Emitter包含了observer的引用,又调用了observer onNext,onComplete,这样下游observer就接收到了上游发射的数据。
总结
Rxjava的流程大概是:
- Observable.create 创建事件源,但并不生产也不发射事件。
- 实现observer接口,但此时没有也无法接受到任何发射来的事件。
- 订阅 observable.subscribe(observer), 此时会调用具体Observable的实现类中的subscribeActual方法,
此时会才会真正触发事件源生产事件,事件源生产出来的事件通过Emitter的onNext,onError,onComplete发射给observer对应的方法由下游observer消费掉。从而完成整个事件流的处理。
observer中的onSubscribe在订阅时即被调用,并传回了Disposable, observer中可以利用Disposable来随时中断事件流的发射。
今天所列举的例子是最简单的一个事件处理流程,没有使用线程调度,Rxjava最强大的就是异步时对线程的调度和随时切换观察者线程,未完待续。
上面分析了Rxjava是如何创建事件源,如何发射事件,何时发射事件,也清楚了上游和下游是如何关联起来的。
下面着重来分析下Rxjava强大的线程调度是如何实现的。
二、RxJava的线程调度机制
简单的例子
private void doSomeWork() {
Observable.create(new ObservableOnSubscribe<String>() {
@Override
public void subscribe(ObservableEmitter<String> e) throws Exception {
Log.i("lx", " subscribe: " + Thread.currentThread().getName());
Thread.sleep(2000);
e.onNext("a");
e.onComplete();
}
}).subscribe(new Observer<String>() {
@Override
public void onSubscribe(Disposable d) {
Log.i("lx", " onSubscribe: " + Thread.currentThread().getName());
}
@Override
public void onNext(String str) {
Log.i("lx", " onNext: " + Thread.currentThread().getName());
}
@Override
public void onError(Throwable e) {
Log.i("lx", " onError: " + Thread.currentThread().getName());
}
@Override
public void onComplete() {
Log.i("lx", " onComplete: " + Thread.currentThread().getName());
}
});
}
运行结果:
com.rxjava2.android.samples I/lx: onSubscribe: main
com.rxjava2.android.samples I/lx: subscribe: main
com.rxjava2.android.samples I/lx: onNext: main
com.rxjava2.android.samples I/lx: onComplete: main
因为此方法笔者是在main线程中调用的,所以没有进行线程调度的情况下,所有方法都运行在main线程中。但我们知道Android的UI线程是不能做网络操作,也不能做耗时操作,所以一般我们把网络或耗时操作都放在非UI线程中执行。接下来我们就来感受下Rxjava强大的线程调度能力。
private void doSomeWork() {
Observable.create(new ObservableOnSubscribe<String>() {
@Override
public void subscribe(ObservableEmitter<String> e) throws Exception {
Log.i("lx", " subscribe: " + Thread.currentThread().getName());
Thread.sleep(2000);
e.onNext("a");
e.onComplete();
}
}).subscribeOn(Schedulers.io()) //增加了这一句
.subscribe(new Observer<String>() {
@Override
public void onSubscribe(Disposable d) {
Log.i("lx", " onSubscribe: " + Thread.currentThread().getName());
}
@Override
public void onNext(String str) {
Log.i("lx", " onNext: " + Thread.currentThread().getName());
}
@Override
public void onError(Throwable e) {
Log.i("lx", " onError: " + Thread.currentThread().getName());
}
@Override
public void onComplete() {
Log.i("lx", " onComplete: " + Thread.currentThread().getName());
}
});
}
运行结果:
com.rxjava2.android.samples I/lx: onSubscribe: main
com.rxjava2.android.samples I/lx: subscribe: RxCachedThreadScheduler-1
com.rxjava2.android.samples I/lx: onNext: RxCachedThreadScheduler-1
com.rxjava2.android.samples I/lx: onComplete: RxCachedThreadScheduler-1
只增加了subscribeOn
这一句代码, 就发生如此神奇的现象,除了onSubscribe方法还运行在main线程(订阅发生的线程)其它方法全部都运行在一个名为RxCachedThreadScheduler-1的线程中。我们来看看rxjava是怎么完成这个线程调度的。
线程调度subscribeOn
首先我们先分析下Schedulers.io()
这个东东。
@NonNull
public static Scheduler io() {
return RxJavaPlugins.onIoScheduler(IO); // hook function
// 等价于
return IO;
}
再看看IO是什么, IO是个static变量,初始化的地方是
IO = RxJavaPlugins.initIoScheduler(new IOTask()); // 又是hook function
// 等价于
IO = callRequireNonNull(new IOTask());
// 等价于
IO = new IOTask().call();
继续看看IOTask
static final class IOTask implements Callable<Scheduler> {
@Override
public Scheduler call() throws Exception {
return IoHolder.DEFAULT;
// 等价于
return new IoScheduler();
}
}
代码层次很深,为了便于记忆,我们再回顾一下:
Schedulers.io()等价于 new IoScheduler() // Schedulers.io()等价于
@NonNull
public static Scheduler io() {
return new IoScheduler();
}
好了,排除了其他干扰代码,接下来看看IoScheduler()是什么东东了
IoScheduler看名称就知道是个IO线程调度器,根据代码注释得知,它就是一个用来创建和缓存线程的线程池。看到这个豁然开朗了,原来Rxjava就是通过这个调度器来调度线程的,至于具体怎么实现我们接着往下看
public IoScheduler() {
this(WORKER_THREAD_FACTORY);
} public IoScheduler(ThreadFactory threadFactory) {
this.threadFactory = threadFactory;
this.pool = new AtomicReference<CachedWorkerPool>(NONE);
start();
} @Override
public void start() {
CachedWorkerPool update = new CachedWorkerPool(KEEP_ALIVE_TIME, KEEP_ALIVE_UNIT, threadFactory);
if (!pool.compareAndSet(NONE, update)) {
update.shutdown();
}
} CachedWorkerPool(long keepAliveTime, TimeUnit unit, ThreadFactory threadFactory) {
this.keepAliveTime = unit != null ? unit.toNanos(keepAliveTime) : 0L;
this.expiringWorkerQueue = new ConcurrentLinkedQueue<ThreadWorker>();
this.allWorkers = new CompositeDisposable();
this.threadFactory = threadFactory; ScheduledExecutorService evictor = null;
Future<?> task = null;
if (unit != null) {
evictor = Executors.newScheduledThreadPool(1, EVICTOR_THREAD_FACTORY);
task = evictor.scheduleWithFixedDelay(this, this.keepAliveTime, this.keepAliveTime, TimeUnit.NANOSECONDS);
}
evictorService = evictor;
evictorTask = task;
}
从上面的代码可以看出,new IoScheduler()
后Rxjava会创建CachedWorkerPool
的线程池,同时也创建并运行了一个名为RxCachedWorkerPoolEvictor
的清除线程,主要作用是清除不再使用的一些线程。
但目前只创建了线程池并没有实际的thread,所以Schedulers.io()
相当于只做了线程调度的前期准备。
OK,终于可以开始分析Rxjava是如何实现线程调度的。回到Demo来看subscribeOn()
方法的内部实现:
public final Observable<T> subscribeOn(Scheduler scheduler) {
ObjectHelper.requireNonNull(scheduler, "scheduler is null");
return RxJavaPlugins.onAssembly(new ObservableSubscribeOn<T>(this, scheduler));
}
很熟悉的代码RxJavaPlugins.onAssembly
,上一篇已经分析过这个方法,就是个hook function, 等价于直接return new ObservableSubscribeOn<T>(this, scheduler);
, 现在知道了这里的scheduler其实就是IoScheduler。
跟踪代码进入ObservableSubscribeOn
,
可以看到这个ObservableSubscribeOn 继承自Observable,并且扩展了一些属性,增加了scheduler。 各位看官,这不就是典型的装饰模式嘛,Rxjava中大量用到了装饰模式,后面还会经常看到这种wrap类。
上篇文章我们已经知道了Observable.subscribe()
方法最终都是调用了对应的实现类的subscribeActual
方法。我们重点分析下subscribeActual
:
@Override
public void subscribeActual(final Observer<? super T> s) {
final SubscribeOnObserver<T> parent = new SubscribeOnObserver<T>(s); // 没有任何线程调度,直接调用的,所以下游的onSubscribe方法没有切换线程,
//本文demo中下游就是观察者,所以我们明白了为什么只有onSubscribe还运行在main线程
s.onSubscribe(parent); parent.setDisposable(scheduler.scheduleDirect(new SubscribeTask(parent)));
}
SubscribeOnObserver
也是装饰模式的体现, 是对下游observer
的一个wrap
,只是添加了Disposable
的管理。
接下来分析最重要的scheduler.scheduleDirect(new SubscribeTask(parent))
// 这个类很简单,就是一个Runnable,最终运行上游的subscribe方法
final class SubscribeTask implements Runnable {
private final SubscribeOnObserver<T> parent; SubscribeTask(SubscribeOnObserver<T> parent) {
this.parent = parent;
} @Override
public void run() {
source.subscribe(parent);
}
}
@NonNull
public Disposable scheduleDirect(@NonNull Runnable run, long delay, @NonNull TimeUnit unit) {
// IoSchedular 中的createWorker()
final Worker w = createWorker();
// hook decoratedRun=run;
final Runnable decoratedRun = RxJavaPlugins.onSchedule(run);
// decoratedRun的wrap,增加了Dispose的管理
DisposeTask task = new DisposeTask(decoratedRun, w);
// 线程调度
w.schedule(task, delay, unit); return task;
}
回到IoSchedular
public Worker createWorker() {
// 工作线程是在此时创建的
return new EventLoopWorker(pool.get());
} public Disposable schedule(@NonNull Runnable action, long delayTime, @NonNull TimeUnit unit) {
if (tasks.isDisposed()) {
// don't schedule, we are unsubscribed
return EmptyDisposable.INSTANCE;
}
// action 中就包含上游subscribe的runnable
return threadWorker.scheduleActual(action, delayTime, unit, tasks);
}
最终线程是在这个方法内调度并执行的。
public ScheduledRunnable scheduleActual(final Runnable run, long delayTime, @NonNull TimeUnit unit, @Nullable DisposableContainer parent) {
// decoratedRun = run, 包含上游subscribe方法的runnable
Runnable decoratedRun = RxJavaPlugins.onSchedule(run); // decoratedRun的wrap,增加了dispose的管理
ScheduledRunnable sr = new ScheduledRunnable(decoratedRun, parent); if (parent != null) {
if (!parent.add(sr)) {
return sr;
}
} // 最终decoratedRun被调度到之前创建或从线程池中取出的线程,
// 也就是说在RxCachedThreadScheduler-x运行
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) {
if (parent != null) {
parent.remove(sr);
}
RxJavaPlugins.onError(ex);
} return sr;
}
至此我们终于明白了Rxjava是如何调度线程并执行的,通过subscribeOn方法将上游生产事件的方法运行在指定的调度线程中。
com.rxjava2.android.samples I/lx: onSubscribe: main
com.rxjava2.android.samples I/lx: subscribe: RxCachedThreadScheduler-1
com.rxjava2.android.samples I/lx: onNext: RxCachedThreadScheduler-1
com.rxjava2.android.samples I/lx: onComplete: RxCachedThreadScheduler-1
从上面的运行结果来看,因为上游生产者已被调度到RxCachedThreadScheduler-1
线程中,同时发射事件并没有切换线程,所以发射后消费事件的onNext onErro onComplete
也在RxCachedThreadScheduler-1
线程中。
总结
Schedulers.io()
等价于new IoScheduler()。
new IoScheduler()
Rxjava
创建了线程池,为后续创建线程做准备,同时创建并运行了一个清理线程RxCachedWorkerPoolEvictor
,定期执行清理任务。subscribeOn()
返回一个ObservableSubscribeOn
对象,它是Observable
的一个装饰类,增加了scheduler
。- 调用
subscribe()
方法,在这个方法调用后,subscribeActual()
被调用,才真正执行了IoSchduler
中的createWorker()
创建线程并运行,最终将上游Observable
的subscribe()
方法调度到新创建的线程中运行。
现在了解了被观察者执行线程是如何被调度到指定线程中执行的,但很多情况下,我们希望观察者(事件下游)处理事件最好在UI线程执行,比如更新UI操作等。下面分析下游何时调度,如何调度由于篇幅问题。
三、Rxjava如何对观察者线程进行调度
简单的例子
private void doSomeWork() {
Observable.create(new ObservableOnSubscribe<String>() {
@Override
public void subscribe(ObservableEmitter<String> e) throws Exception {
Log.i("lx", " subscribe: " + Thread.currentThread().getName());
e.onNext("a");
e.onComplete();
}
}).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<String>() {
@Override
public void onSubscribe(Disposable d) {
Log.i("lx", " onSubscribe: " + Thread.currentThread().getName());
}
@Override
public void onNext(String str) {
Log.i("lx", " onNext: " + Thread.currentThread().getName());
}
@Override
public void onError(Throwable e) {
Log.i("lx", " onError: " + Thread.currentThread().getName());
}
@Override
public void onComplete() {
Log.i("lx", " onComplete: " + Thread.currentThread().getName());
}
});
}
看看运行结果:
com.rxjava2.android.samples I/lx: onSubscribe: main
com.rxjava2.android.samples I/lx: subscribe: RxCachedThreadScheduler-1
com.rxjava2.android.samples I/lx: onNext: main
com.rxjava2.android.samples I/lx: onComplete: main
从结果可以看出,事件的生产线程运行在RxCachedThreadScheduler-1中,而事件的消费线程则被调度到了main线程中。关键代码是因为这句.observeOn(AndroidSchedulers.mainThread())
。 下面我们着重分析下这句代码都做了哪些事情。
AndroidSchedulers.mainThread()
先来看看AndroidSchedulers.mainThread()
是什么?贴代码
/** A {@link Scheduler} which executes actions on the Android main thread. */
public static Scheduler mainThread() {
return RxAndroidPlugins.onMainThreadScheduler(MAIN_THREAD);
}
注释已经说的很明白了,是一个在主线程执行任务的scheduler,接着看
private static final Scheduler MAIN_THREAD = RxAndroidPlugins.initMainThreadScheduler(
new Callable<Scheduler>() {
@Override public Scheduler call() throws Exception {
return MainHolder.DEFAULT;
}
}); public static Scheduler initMainThreadScheduler(Callable<Scheduler> scheduler) {
if (scheduler == null) {
throw new NullPointerException("scheduler == null");
}
Function<Callable<Scheduler>, Scheduler> f = onInitMainThreadHandler;
if (f == null) {
return callRequireNonNull(scheduler);
}
return applyRequireNonNull(f, scheduler);
}
代码很简单,这个AndroidSchedulers.mainThread()
想当于new HandlerScheduler(new Handler(Looper.getMainLooper()))
,原来是利用Android
的Handler
来调度到main
线程的。
我们再看看HandlerScheduler
,它与我们上节分析的IOScheduler
类似,都是继承自Scheduler
,所以AndroidSchedulers.mainThread()
其实就是是创建了一个运行在main thread
上的scheduler。
好了,我们再回过头来看observeOn
方法。
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));
}
重点是这个new ObservableObserveOn
,看名字是不是有种似成相识的感觉,还记得上篇的ObservableSubscribeOn
吗? 它俩就是亲兄弟,是继承自同一个父类。
重点还是这个方法,我们前文已经提到了,Observable的subscribe方法最终都是调用subscribeActual
方法。下面看看这个方法的实现:
@Override
protected void subscribeActual(Observer<? super T> observer) {
// scheduler 就是前面提到的 HandlerScheduler,所以进入else分支
if (scheduler instanceof TrampolineScheduler) {
source.subscribe(observer);
} else {
// 创建 HandlerWorker
Scheduler.Worker w = scheduler.createWorker();
// 调用上游Observable的subscribe,将订阅向上传递
source.subscribe(new ObserveOnObserver<T>(observer, w, delayError, bufferSize));
}
}
从上面代码可以看到使用了ObserveOnObserver
类对observer
进行装饰,好了,我们再来看看ObserveOnObserver
。
我们已经知道了,事件源发射的事件,是通过observer的onNext
,onError
,onComplete
发射到下游的。所以看看ObserveOnObserver
的这三个方法是如何实现的。
由于篇幅问题,我们只分析onNext
方法,onError
和onComplete
方法有兴趣的同学可以自己分析下。
@Override
public void onNext(T t) {
if (done) {
return;
} // 如果是非异步方式,将上游发射的时间加入到队列
if (sourceMode != QueueDisposable.ASYNC) {
queue.offer(t);
}
schedule();
} void schedule() {
// 保证只有唯一任务在运行
if (getAndIncrement() == 0) {
// 调用的就是HandlerWorker的schedule方法
worker.schedule(this);
}
} @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;
}
schedule
方法将传入的run
调度到对应的handle
所在的线程来执行,这个例子里就是有main
线程来完成。 再回去看看前面传入的run
吧。
回到ObserveOnObserver
中的run
方法:
@Override
public void run() {
// 此例子中代码不会进入这个分支,至于这个drainFused是什么,后面章节再讨论。
if (outputFused) {
drainFused();
} else {
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; try {
// 从队列中queue中取出事件
v = q.poll();
} catch (Throwable ex) {
Exceptions.throwIfFatal(ex);
s.dispose();
q.clear();
a.onError(ex);
worker.dispose();
return;
}
boolean empty = v == null; if (checkTerminated(d, empty, a)) {
return;
} if (empty) {
break;
}
//调用下游observer的onNext将事件v发射出去
a.onNext(v);
} missed = addAndGet(-missed);
if (missed == 0) {
break;
}
}
}
至此我们明白了RXjava是如何调度消费者线程了。
消费者线程调度流程概括
Rxjava调度消费者现在的流程,以observeOn(AndroidSchedulers.mainThread())
为例。
AndroidSchedulers.mainThread()
先创建一个包含handler
的Scheduler
, 这个handler
是主线程的handler
。observeOn
方法创建ObservableObserveOn
,它是上游Observable
的一个装饰类,其中包含前面创建的Scheduler
和bufferSize
等.- 当订阅方法
subscribe
被调用后,ObservableObserveOn
的subscribeActual
方法创建Scheduler.Worker
并调用上游的subscribe
方法,同时将自身接收的参数'observer'用装饰类ObserveOnObserver
装饰后传递给上游。 - 当上游调用被
ObserveOnObserver
的onNext
、onError
和onComplete
方法时,ObserveOnObserver
将上游发送的事件通通加入到队列queue
中,然后再调用scheduler
将处理事件的方法调度到对应的线程中(本例会调度到main thread)。 处理事件的方法将queue
中保存的事件取出来,调用下游原始的observer再发射出去。 - 经过以上流程,下游处理事件的消费者线程就运行在了
observeOn
调度后的thread中。
总结
经过前面两节的分析,我们已经明白了Rxjava是如何对线程进行调度的。
- Rxjava的
subscribe
方法是由下游一步步向上游进行传递的。会调用上游的subscribe
,直到调用到事件源。
如: source.subscribe(xxx);
而上游的source
往往是经过装饰后的Observable
, Rxjava就是利用ObservableSubscribeOn
将subscribe
方法调度到了指定线程运行,生产者线程最终会运行在被调度后的线程中。但多次调用subscribeOn
方法会怎么样呢? 我们知道因为subscribe
方法是由下而上传递的,所以事件源的生产者线程最终都只会运行在第一次执行subscribeOn
所调度的线程中,换句话就是多次调用subscribeOn
方法,只有第一次有效。
- Rxjava发射事件是由上而下发射的,上游的
onNext
、onError
、onComplete
方法会调用下游传入的observer的对应方法。往往下游传递的observer对象也是经过装饰后的observer对象。Rxjava就是利用ObserveOnObserver
将执行线程调度后,再调用下游对应的onNext
、onError
、onComplete
方法,这样下游消费者就运行再了指定的线程内。 那么多次调用observeOn
调度不同的线程会怎么样呢? 因为事件是由上而下发射的,所以每次用observeOn
切换完线程后,对下游的事件消费都有效,比如下游的map操作符。最终的事件消费线程运行在最后一个observeOn
切换后线程中。 - 另外通过源码可以看到
onSubscribe
运行在subscribe
的调用线程中,这个就不具体分析了。
RxJava2 源码分析的更多相关文章
- RxJava2 中多种取消订阅 dispose 的方法梳理( 源码分析 )
Github 相关代码: Github地址 一直感觉 RxJava2 的取消订阅有点混乱, 这样也能取消, 那样也能取消, 没能系统起来的感觉就像掉进了盘丝洞, 迷乱… 下面说说这几种情况 几种取消的 ...
- RxJava2 源码解析(二)
概述 承接上一篇RxJava2 源码解析(一),本系列我们的目的: 知道源头(Observable)是如何将数据发送出去的. 知道终点(Observer)是如何接收到数据的. 何时将源头和 ...
- RxJava 2.x 源码分析
本次分析的 RxJava 版本信息如下: 12 implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'implementation 'io.reac ...
- RxJava2源码解析(二)
title: RxJava2源码解析(二) categories: 源码解析 tags: 源码解析 rxJava2 前言 本篇主要解析RxJava的线程切换的原理实现 subscribeOn 首先, ...
- ABP源码分析一:整体项目结构及目录
ABP是一套非常优秀的web应用程序架构,适合用来搭建集中式架构的web应用程序. 整个Abp的Infrastructure是以Abp这个package为核心模块(core)+15个模块(module ...
- HashMap与TreeMap源码分析
1. 引言 在红黑树--算法导论(15)中学习了红黑树的原理.本来打算自己来试着实现一下,然而在看了JDK(1.8.0)TreeMap的源码后恍然发现原来它就是利用红黑树实现的(很惭愧学了Ja ...
- nginx源码分析之网络初始化
nginx作为一个高性能的HTTP服务器,网络的处理是其核心,了解网络的初始化有助于加深对nginx网络处理的了解,本文主要通过nginx的源代码来分析其网络初始化. 从配置文件中读取初始化信息 与网 ...
- zookeeper源码分析之五服务端(集群leader)处理请求流程
leader的实现类为LeaderZooKeeperServer,它间接继承自标准ZookeeperServer.它规定了请求到达leader时需要经历的路径: PrepRequestProcesso ...
- zookeeper源码分析之四服务端(单机)处理请求流程
上文: zookeeper源码分析之一服务端启动过程 中,我们介绍了zookeeper服务器的启动过程,其中单机是ZookeeperServer启动,集群使用QuorumPeer启动,那么这次我们分析 ...
随机推荐
- Haskell语言学习笔记(64)Lens(4)
安装 lens-tutorial Control.Lens.Tutorial $ cabal install lens-tutorial Installed lens-tutorial-1.0.3 P ...
- Java Magic. Part 2: 0xCAFEBABE
Java Magic. Part 2: 0xCAFEBABE @(Base)[JDK, magic, 黑魔法] 转载请写明:原文地址 英文原文 系列文章: -Java Magic. Part 1: j ...
- hibernate事务隔离机制
事务的基本概念 ACID:A是atomicity(原子性),C是consistency(一致性),I是isolation(隔离性),D是durability(持久性) 事务隔离级别从低到高: 读取未提 ...
- Mysql一些记忆
mysql修改密码报错是yum 安装mysql5.7 是 出现无法登陆问题以及mysql error You must reset your password using ALTER USER sta ...
- 关于HSTS安全协议的全面详细解析
HTTP 严格传输安全(HSTS)是一种安全功能,web 服务器通过它来告诉浏览器仅用 HTTPS 来与之通讯,而不是使用 HTTP.HSTS是网站从HTTP到HTTPS中网站性能及安全优化非常重要的 ...
- wordpress 下载主题模板、更新报错 No working transports found解决办法
出错原因是PHP没有开启curl. windows下开启方法如下 1. 将php.ini中的;extension=php_curl.dll前的分号去掉, 2. 将php中libeay32.ll, ss ...
- Poor Warehouse Keeper
Poor Warehouse Keeper http://acm.hdu.edu.cn/showproblem.php?pid=4803 Jenny is a warehouse keeper. He ...
- MonkeyRunner原理初步--Android自动化测试学习历程
章节:自动化基础篇——MonkeyRunner原理初步 主要讲解内容及笔记: 一.理论知识和脚本演示 最佳方式是上官网文档去查看monkeyrunner的介绍,官网上不去,就找了一个本地的androi ...
- 删除排序数组中的重复数字 II · Remove Duplicates from Sorted Array II
重复一次 [抄题]: 给定一个排序数组,在原数组中删除重复出现的数字,使得每个元素只出现一次,并且返回新的数组的长度. 不要使用额外的数组空间,必须在原地没有额外空间的条件下完成. [思维问题]: [ ...
- 启动apache时,出现httpd: Could not reliably determine the server\'s fully qualified domain name, using 127.0.0.1 for ServerName
1.通过vi打开apache的配置文件httpd.conf > vi /data/apache/conf/httpd.conf 2.找到#ServerName www.example.com:8 ...