RxJava简单介绍
RxJava现在几乎每个Android项目中都有它的身影,RxJava是使用了Rx(ReactiveX)函数库的语言库,Rx是一个函数库,让开发者可以利用可观察序列和LINQ风格查询操作符来编写异步和基于事件的程序,除了RxJava,Rx几乎支持了全部的流行编程语言,例如:RxJS、Rx.NET等等。
RxJava的优点和使用方法这篇文章不做介绍,今天关注一下框架内部原理:比如我们平时用RxJava的时候会使用subscribeOn(Schedulers.io())和observeOn(AndroidSchedulers.mainThread())来切换线程,有没有对其内部的实现感兴趣呢?
读这篇文章之前可以先看看这篇,有助于理解流程关系 《码上理解— 手撕RxJava订阅关系,事件发送和接收》
文章目的
通过看源码的实现过程,来理解RxJava在Android平台上如何通过subscribeOn(Schedulers.io())方法实现线程调度的
环境搭建和代码示例
示例是基于RxJava2
配置和代码很简单,如下
implementation 'io.reactivex.rxjava2:rxjava:2.1.0'
implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'
public class MainActivity extends AppCompatActivity {
private Disposable disposable;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
rxJava();
}
public void rxJava() {
Observable.create(new ObservableOnSubscribe<String>() {
@Override
public void subscribe(ObservableEmitter<String> e) throws Exception {
e.onNext("事件1");
}
})
.subscribeOn(Schedulers.io())
//.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<String>() {
@Override
public void onSubscribe(Disposable d) {
Log.i("RxJava",s+","+Thread.currentThread().getName());
disposable = d;
}
@Override
public void onNext(String s) {
Log.i("RxJava",s);
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
if (disposable != null)
if (!disposable.isDisposed())
disposable.dispose();
}
}
运行后日志打印
I/RxJava: 订阅
I/RxJava: 事件1,RxCachedThreadScheduler-1
文章有点长,可以先拉到底部,先看总结,然后再一步一步跟代码
分析subscribeOn(Schedulers.io())
我们先尝试看一下subscribeOn(Schedulers.io())这个方法
点击subscribe方法进入源码
@CheckReturnValue
@SchedulerSupport(SchedulerSupport.CUSTOM)
public final Observable<T> subscribeOn(Scheduler scheduler) {
ObjectHelper.requireNonNull(scheduler, "scheduler is null");
return RxJavaPlugins.onAssembly(new ObservableSubscribeOn<T>(this, scheduler));
}
发现进入了抽象类Observable的subscribeOn方法,方法的参数是Scheduler 类型,Scheduler的翻译是调度器,进一步跟踪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 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);
}
... ...
}
由于Schedulers.io()就是方法实参,所以我们推断Schedulers.io()就是Scheduler的实现类,换句话说Schedulers.io()就是调度器,那我们先看以下这个调度器是什么吧!
Schedulers.io()
我们尝试点击Schedulers类,跳转源码,发现用到了策略模式,Schedulers.io()是其中一个策略
常见的策略的使用场景了解一下
1.Schedulers.io(): I/O 操作(读写文件、读写数据库、网络信息交互等)所使用的 Scheduler。行为模式和 newThread() 差不多,区别在于 io() 的内部实现是是用一个无数量上限的线程池,可以重用空闲的线程,因此多数情况下 io() 比 newThread() 更有效率。不要把计算工作放在 io() 中,可以避免创建不必要的线程。
2.Schedulers.computation(): 计算所使用的 Scheduler。这个计算指的是 CPU 密集型计算,即不会被 I/O 等操作限制性能的操作,例如图形的计算。这个 Scheduler 使用的固定的线程池,大小为 CPU 核数。不要把 I/O 操作放在 computation() 中,否则 I/O 操作的等待时间会浪费 CPU。
3.另外, Android 还有一个专用的 AndroidSchedulers.mainThread(),它指定的操作将在 Android 主线程运行。
我们看一下Schedulers.io()具体的实现方式
@NonNull
public static Scheduler io() {
return RxJavaPlugins.onIoScheduler(IO);
}
发现返回了RxJavaPlugins.onIoScheduler,这个类RxJavaPlugins下的方法其实是实现hook,由于我们当前不关心hook,先不用管它,它方法内返回的其实就是IO对象
/**
* Calls the associated hook function.
* @param defaultScheduler the hook's input value
* @return the value returned by the hook
*/
@NonNull
public static Scheduler onIoScheduler(@NonNull Scheduler defaultScheduler) {
Function<? super Scheduler, ? extends Scheduler> f = onIoHandler;
if (f == null) {
return defaultScheduler;
}
return apply(f, defaultScheduler);
}
ok,现在我们看一下IO是哪来的,发现其实在类中的静态代码块中初始化的
static {
SINGLE = RxJavaPlugins.initSingleScheduler(new SingleTask());
COMPUTATION = RxJavaPlugins.initComputationScheduler(new ComputationTask());
//这里初始化了调度器IO
IO = RxJavaPlugins.initIoScheduler(new IOTask());
TRAMPOLINE = TrampolineScheduler.instance();
NEW_THREAD = RxJavaPlugins.initNewThreadScheduler(new NewThreadTask());
}
又看到了RxJavaPlugins类,我们先不去管它,直接看new IOTask()
static final class IOTask implements Callable<Scheduler> {
@Override
public Scheduler call() throws Exception {
return IoHolder.DEFAULT;
}
}
发现他是一个任务,返回值是Scheduler 调度器,那它是从哪里执行这个任务的呢,我们这时可以看RxJavaPlugins.initNewThreadScheduler这个方法了
@NonNull
public static Scheduler initIoScheduler(@NonNull Callable<Scheduler> defaultScheduler) {
ObjectHelper.requireNonNull(defaultScheduler, "Scheduler Callable can't be null");
//代码中如果没有实现onInitIoHandler,这里始终是null的
Function<? super Callable<Scheduler>, ? extends Scheduler> f = onInitIoHandler;
if (f == null) {
return callRequireNonNull(defaultScheduler);
}
return applyRequireNonNull(f, defaultScheduler);
}
我们传入了Callable,返回的是Scheduler ,说明在这个方法中执行了IOTask 任务,于是我们进一步看方法callRequireNonNull(defaultScheduler)。
这里还要说明一下,如果我们没有自己实现hook方法setInitIoSchedulerHandler(), onInitIoHandler这里始终是null,所以我们直接看一个参数的方法callRequireNonNull
@NonNull
static Scheduler callRequireNonNull(@NonNull Callable<Scheduler> s) {
try {
return ObjectHelper.requireNonNull(s.call(), "Scheduler Callable result can't be null");
} catch (Throwable ex) {
throw ExceptionHelper.wrapOrThrow(ex);
}
}
ok,我们发现s.call(),执行了IOTask任务。我们再回到IOTask,我们看看到底返回的调度器是个什么东东
static final class IoHolder {
static final Scheduler DEFAULT = new IoScheduler();
}
发现IoHolder 其实是Schedulers的静态内部类,静态内部类中又创建了静态对象IoScheduler,看一下
IoScheduler
/**
* Scheduler that creates and caches a set of thread pools and reuses them if possible.
*/
public final class IoScheduler extends Scheduler {
static {
...
//工作线程的线程工厂
WORKER_THREAD_FACTORY = new RxThreadFactory(WORKER_THREAD_NAME_PREFIX, priority);
//线程池
NONE = new CachedWorkerPool(0, null, WORKER_THREAD_FACTORY);
NONE.shutdown();
}
//无参构造
public IoScheduler() {
this(WORKER_THREAD_FACTORY);
}
//传入了用于创建工作线程的线程工厂
public IoScheduler(ThreadFactory threadFactory) {
this.threadFactory = threadFactory;
this.pool = new AtomicReference<CachedWorkerPool>(NONE);
start();
}
public IoScheduler() {
this(WORKER_THREAD_FACTORY);
}
// 实现了 Scheduler 的createWorker方法
@NonNull
@Override
public Worker createWorker() {
return new EventLoopWorker(pool.get());
}
...
//实现了Scheduler.Worker 抽象类
static final class EventLoopWorker extends Scheduler.Worker {
...
@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);
}
...
}
}
上面的代码我们可以看出,调度器里其实是创建了线程池,所以,此处可以推测.subscribeOn(Schedulers.io())方法将每一个事件当作任务放入线程池执行,从而达到线程血环的目的。
再注意一点,IO调度器IoScheduler类中实现了一个抽象方法,一个抽象类,还记得文章一开始混眼熟的那个类吗,ok,我们再眼熟一下因为一会要用
到目前为止,我们知道Schedulers.io()其实就是创建了IoScheduler,它的本质是一个线程池,由方法subscribeOn(Schedulers.io()),IoScheduler对象丢给了subscribeOn方法,那我们进一步看一下subscribeOn方法中究竟是卖的什么药
subscribeOn()
subscribeOn我们接着看
@CheckReturnValue
@SchedulerSupport(SchedulerSupport.CUSTOM)
public final Observable<T> subscribeOn(Scheduler scheduler) {
ObjectHelper.requireNonNull(scheduler, "scheduler is null");
return RxJavaPlugins.onAssembly(new ObservableSubscribeOn<T>(this, scheduler));
}
前面如果都跟者看过来的话,我们就可以直接进入ObservableSubscribeOn类了(RxJavaPlugins.onAssembly()方法返回的就是ObservableSubscribeOn对象)
ObservableSubscribeOn类我全粘过来了,代码比较长
public final class ObservableSubscribeOn<T> extends AbstractObservableWithUpstream<T, T> {
final Scheduler scheduler;//IoScheduler
public ObservableSubscribeOn(ObservableSource<T> source, Scheduler scheduler) {
super(source);
this.scheduler = scheduler;
}
@Override
public void subscribeActual(final Observer<? super T> s) {
//包装一层,将观察者Observer放入SubscribeOnObserver对象中
final SubscribeOnObserver<T> parent = new SubscribeOnObserver<T>(s);
//调用观察者Observer的onSubscribe方法
s.onSubscribe(parent);
parent.setDisposable(scheduler.scheduleDirect(new SubscribeTask(parent)));
}
static final class SubscribeOnObserver<T> extends AtomicReference<Disposable> implements Observer<T>, Disposable {
private static final long serialVersionUID = 8094547886072529208L;
final Observer<? super T> actual;
final AtomicReference<Disposable> s;
SubscribeOnObserver(Observer<? super T> actual) {
this.actual = actual;
this.s = new AtomicReference<Disposable>();
}
@Override
public void onSubscribe(Disposable s) {
DisposableHelper.setOnce(this.s, s);
}
@Override
public void onNext(T t) {
actual.onNext(t);
}
@Override
public void onError(Throwable t) {
actual.onError(t);
}
@Override
public void onComplete() {
actual.onComplete();
}
@Override
public void dispose() {
DisposableHelper.dispose(s);
DisposableHelper.dispose(this);
}
@Override
public boolean isDisposed() {
return DisposableHelper.isDisposed(get());
}
void setDisposable(Disposable d) {
DisposableHelper.setOnce(this, d);
}
}
final class SubscribeTask implements Runnable {
private final SubscribeOnObserver<T> parent;
SubscribeTask(SubscribeOnObserver<T> parent) {
this.parent = parent;
}
@Override
public void run() {
source.subscribe(parent);
}
}
}
拿到这个类,我们可以知道ObservableSubscribeOn对象中有传入的IoScheduler调度器,有一个subscribeActual方法,有一个SubscribeOnObserver静态内部类,还有一个订阅任务SubscribeTask。
如果看过我另一篇文章的码上理解— 手撕RxJava订阅关系,事件发送和接收
应该知道,subscribeActual这个方法其实是由下游subscribe方法调用,也就是执行subscribe就执行subscribeActual
那重点就是subscribeActual方法,看一下subscribeActual方法干了些什么
@Override
public void subscribeActual(final Observer<? super T> s) {
//包装一层,将观察者Observer放入SubscribeOnObserver对象中
final SubscribeOnObserver<T> parent = new SubscribeOnObserver<T>(s);
//调用观察者Observer的onSubscribe方法
s.onSubscribe(parent);
//最后创建了一个任务SubscribeTask,把任务丢给IoScheduler调度器
parent.setDisposable(scheduler.scheduleDirect(new SubscribeTask(parent)));
}
先把下游的Observer对象包装进SubscribeOnObserver对象,然后执行了observer的onSubscribe方法,表示订阅完成,最后创建了一个任务SubscribeTask,把任务丢给IoScheduler调度器
那IoScheduler的scheduleDirect方法具体干了些什么呢,还记得文章开头混脸熟的Scheduler类吗?
scheduler.scheduleDirect实际上就是调用到这里了,我们再看一下三个参数的scheduleDirect方法
public abstract class Scheduler {
@NonNull
public Disposable scheduleDirect(@NonNull Runnable run, long delay, @NonNull TimeUnit unit) {
//还记得IoScheduler 的createWorker方法吗
final Worker w = createWorker();
// SubscribeTask
final Runnable decoratedRun = RxJavaPlugins.onSchedule(run);
// 给SubscribeTask包装一层DisposeTask,实现了Disposable接口
DisposeTask task = new DisposeTask(decoratedRun, w);
// 执行 EventLoopWorker的schedule方法
w.schedule(task, delay, unit);
return task;
}
}
上面注释已经解释了,scheduleDirect方法就是将SubscribeTask丢给了schedule方法,那看一下schedule方法具体干了啥
方法中线程池executor执行了SubscribeTask任务,我们再看一下SubscribeTask的run方法中执行的是什么
public final class ObservableSubscribeOn<T> extends AbstractObservableWithUpstream<T, T> {
final Scheduler scheduler;
public ObservableSubscribeOn(ObservableSource<T> source, Scheduler scheduler) {
super(source);
this.scheduler = scheduler;
}
...
...
final class SubscribeTask implements Runnable {
private final SubscribeOnObserver<T> parent;
SubscribeTask(SubscribeOnObserver<T> parent) {
this.parent = parent;
}
@Override
public void run() {
//执行了上游的subscribe方法
source.subscribe(parent);
}
}
}
run方法中调用了source的subscribe方法。source是SubscribeOnObserver构造方法传入进来的,它其实就是Observable
那source.subscribe就是调用的Observable的subscribe方法,ok,找一下subscribe
如果看过我另一篇文章的码上理解— 手撕RxJava订阅关系,事件发送和接收的老铁应该知道,subscribeActual是抽象方法,subscribeActual(observer)是跳转到哪里,没错是Observable.create创建出的ObservableCreate对象里的subscribeActual方法。
还记得subscribeActual(observer)的参数observer是什么吗,是被SubscribeOnObserver包装的观察者Observer,来看一下ObservableCreate对象中的subscribeActual方法做了什么
上图中为什么说e.onNext方法执行在子线程中呢?
因为下游执行subscribe方法的时候,
1.先将Observer观察者包装到SubscribeOnObserver中去(装饰模式)
2.然后执行了Observer的onSubscribe回调,订阅完成
3.创建一个任务SubscribeTask,将装有观察者Observer的包裹SubscribeOnObserver传给这个任务,方便在run方法中将包裹SubscribeOnObserver传给上游,上游拿到包裹可以再进行添加包裹或者解开包裹执行Observer的onNext回调或其它回调
4.将任务SubscribeTask丢进IO调度器IoScheduler中的线程池并submit执行
5.SubscribeTask中的 source.subscribe(parent);将包裹SubscribeOnObserver传给上游,由于此时已经运行在线程池中了,所以上游的subscribeActual方法是运行在子线程中,ObservableOnSubscribe的subscribe回调是在subscribeActual方法中调用的,所以subscribe方法也是运行在子线程,e.onNext在方法subscribe里调用,所以e.onNext方法执行也在子线程中。没毛病。
总结
RxJava通过subscribeOn(Schedulers.io())切换子线程的原理是将subscribeOn的上游都放入线程池中执行;从这里也可以推断出另一个结论,当有多个subscribeOn的时候,只有上游的第一个subscribeOn有效,换句话说程序会运行在上游第一个subscribeOn()所切换的线程里。
最后来张图总结一下