详解-RxJava2-的线程切换原理

void schedule() {
if (getAndIncrement() == 0) {
//直接调用了 worker 的 schedule 方法,需要注意的是这里他把自己传了进去
worker.schedule(this);
}
}

现在我先把把 schedule(Runnable run) 贴出来

public Disposable schedule(@NonNull Runnable run) {
return schedule(run, 0L, TimeUnit.NANOSECONDS);
}

  1. 我们看到这个他接收的参数是一个 Runnable,这是怎么回事呢,我们看一下 ObserveOnObserver 对象,他不但实现了 Observer 接口并且也实现了 Runnable 接口
  2. 接下看,继续调用 schedule( Runnable action, long delayTime, TimeUnit unit) 方法,但是这个方法是个抽象方法,这里我们就假设这里这个 worker 是 IO 线程,所以我直接贴 IoScheduler 的代码了

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);
}

然后再贴一下 scheduleActual 的方法

public ScheduledRunnable scheduleActual(final Runnable run, long delayTime, @NonNull TimeUnit unit, @Nullable DisposableContainer parent) {
Runnable decoratedRun = RxJavaPlugins.onSchedule(run);
//就是个 Runnable
ScheduledRunnable sr = new ScheduledRunnable(decoratedRun, parent);

if (parent != null) {
if (!parent.add(sr)) {
return sr;
}
}

Future<?> f;
try {
//判断延迟时间,然后使用线程池运行 Runnable
if (delayTime <= 0) {
f = executor.submit((Callable)sr);
} else {
f = executor.schedule((Callable)sr, delayTime, unit);
}
sr.setFuture(f);
} catch (RejectedExecutionException ex) {
if (parent != null) {
parent.remove(sr);
}
RxJavaPlugins.onError(ex);
}
return sr;
}

这样一来就会在相应的线程中运行 ObserveOnObserver 的 run 方法

public void run() {
//这个地方具体的我还没有搞明白,大概就是在这个方法里调用 onNext() ,然后 observeOn() 操作符之后的监听者的运行线程就变了
if (outputFused) {
drainFused();
} else {
drainNormal();
}
}

二、subscribeOn() 的线程切换原理

PS:这个切换原理其实和 observeOn() 原理很像

跟 observeOn() 一样,只不过这个操作的对象是 ObservableSubscribeOn, 这个对象也是同样的代码逻辑,运行 subscribe() 方法,然后调用 subscribeActual() 方法,所以就直接贴 subscribeActual() 的代码

public void subscribeActual(final Observer<? super T> s) {
//创建与之绑定的 SubscribeOnObserver
final SubscribeOnObserver parent = new SubscribeOnObserver(s);
s.onSubscribe(parent);
//1. 创建 SubscribeTask 实际上就是个 Runnable
//2. 然后调用 scheduler.scheduleDirect 方法
parent.setDisposable(scheduler.scheduleDirect(new SubscribeTask(parent)));
}

我们看一下 scheduleDirect 的方法

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();
final Runnable decoratedRun = RxJavaPlugins.onSchedule(run);
//一个 Runnable 具体作用没分析
DisposeTask task = new DisposeTask(decoratedRun, w);
//这个代码看着熟悉吗 没错上面 observeOn 提到过,知道它是运行 Runnable 我们就直接看 Runnable 里面的 run() 了
w.schedule(task, delay, unit);
return task;
}

我们看一下 DisposeTask 的 run()

public void run() {
runner = Thread.currentThread();
try {
decoratedRun.run();
} finally {
dispose();
runner = null;
}
}

调来调去我们又回到了 SubscribeTask 的 run()

public void run() {
source.subscribe(parent);
}

这个地方的运行线程已经被切换了,他又开始往上一层层的去订阅,所以 create(new ObservableOnSubscribe(){})这个匿名实现接口运行 subscribe 的线程运行环境都被改变了,再去调用 onNext() 等方法线程环境也是被改变的

为什么 subscribeOn() 只有第一次切换有效

写到这里我们这个问题也就能回答了
因为 RxJava 最终能影响 ObservableOnSubscribe 这个匿名实现接口的运行环境的只能是最后一次运行的 subscribeOn() ,又因为 RxJava 订阅的时候是从下往上订阅,所以从上往下第一个 subscribeOn() 就是最后运行的,这就造成了写多个 subscribeOn() 并没有什么乱用的现象。


分析一下 RxAndroid

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

其实 RxAndroid 里面并没有什么复杂的代码,他其实只是提供一个能切换到 Android 主线程线程调度器。

其实它的原理和 RxJava 自带的那些线程调度器一样,如果你想了解 RxJava 的 IO 线程池,什么的可以自己看一看,我这里分析 RxAndroid 主要有以下几点原因

  1. 弄清楚 RxAndroid 这个库的具体作用
  2. 弄清楚他是怎么就能把线程切换到主线程(他是怎么提供的主线程环境)
  3. 弄清楚线程调度器的运行原理
  4. 最重要的是它相对于 RxJava 自带的那些调度器,他比较简单容易分析

###正文开始

首先我们找一下入口 AndroidSchedulers.mainThread() 这个地方应该是就是入口了,我们看一下 AndroidSchedulers 这个类的源码吧,总共也没几行

private static final class MainHolder {
static final Scheduler DEFAULT = new HandlerScheduler(new Handler(Looper.getMainLooper()));
}

private static final Scheduler MAIN_THREAD = RxAndroidPlugins.initMainThreadScheduler(
new Callable() {
@Override public Scheduler call() throws Exception {
return MainHolder.DEFAULT;
}
}
);

public static Scheduler mainThread() {
return RxAndroidPlugins.onMainThreadScheduler(MAIN_THREAD);
}

public static Scheduler from(Looper looper) {
if (looper == null) throw new NullPointerException(“looper == null”);
return new HandlerScheduler(new Handler(looper));
}

这个应该不用我多说大家都能看明白,看到这里我们基本上明白了 RxAndroid 就是通过 Handler 来拿到主线程的

我们拿 subscribeOn() 中的一些流程来说

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;
}

首先我们看到调用了 createWorker() 这是个抽象方法我们找到具体实现类 HandlerScheduler

public Worker createWorker() {
return new HandlerWorker(handler);
}

单纯的创建一个 Worker 并把主线程的 Handler 传进去,然后调用 Worker 的 schedule() 方法

public Disposable schedule(Runnable run, long delay, TimeUnit unit) {
/忽略一些代码/
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, unit.toMillis(delay));

if (disposed) {
handler.removeCallbacks(scheduled);
return Disposables.disposed();
}
return scheduled;
}

到这里看明白 RxJava 如何通过 RxAndroid 来切换到主线程运行,其实 RxAndroid 的核心就是 Handler


总结

本篇参考 RxJava 2.1.12 与 RxAndroid:2.0.2 源码
不得不说 Handler 在安卓中的地位真的是很牛逼
见解不到的地方欢迎大家指出

原文链接:https://www.jianshu.com/p/a9ebf730cd08

【附】相关架构及资料

image

资料领取

点赞+加群免费获取 Android IOC架构设计

加群领取获取往期Android高级架构资料、源码、笔记、视频。高级UI、性能优化、架构师课程、NDK、混合式开发(ReactNative+Weex)微信小程序、Flutter全方面的Android进阶实践技术,群内还有技术大牛一起讨论交流解决问题。

总结

**其实上面说了这么多,钱是永远赚不完的,在这个知识付费的时代,知识技能提升才是是根本!我作为一名8年的高级工程师,知识技能已经学习的差不多。**在看这篇文章的可能有刚刚入门,刚刚开始工作,或者大佬级人物。

像刚刚开始学Android开发小白想要快速提升自己,最快捷的方式,就是有人可以带着你一起分析,这样学习起来最为高效,所以这里分享一套高手学习的源码和框架视频等精品Android架构师教程,保证你学了以后保证薪资上升一个台阶。

这么重要的事情说三遍啦!点赞+点赞+点赞!

【Android高级架构师系统学习资料】高级架构师进阶必备——设计思想解读开源框架

第一章、热修复设计
第二章、插件化框架设计
第三章、组件化框架设计
第四章、图片加载框架
第五章、网络访问框架设计
第六章、RXJava 响应式编程框架设计
第七章、IOC 架构设计
第八章、Android 架构组件 Jetpack


《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!
读开源框架

第一章、热修复设计
第二章、插件化框架设计
第三章、组件化框架设计
第四章、图片加载框架
第五章、网络访问框架设计
第六章、RXJava 响应式编程框架设计
第七章、IOC 架构设计
第八章、Android 架构组件 Jetpack

[外链图片转存中…(img-0FnBpzsi-1715395182344)]
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!

  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值