.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer() {
@Override
public void onSubscribe(Disposable d) {
Log.d(TAG, “Observer onSubscribe() 所在线程为 :” + Thread.currentThread().getName());
}
@Override
public void onNext(String s) {
Log.d(TAG, “Observer onNext() 所在线程为 :” + Thread.currentThread().getName());
}
@Override
public void onError(Throwable e) {
Log.d(TAG, “Observer onError() 所在线程为 :” + Thread.currentThread().getName());
}
@Override
public void onComplete() {
Log.d(TAG, “Observer onComplete() 所在线程为 :” + Thread.currentThread().getName());
}
});
}
}.start();
输出结果为:
Thread run() 所在线程为 :Thread-2
Observer onSubscribe() 所在线程为 :Thread-2
Observable subscribe() 所在线程为 :RxCachedThreadScheduler-1
Observer onNext() 所在线程为 :main
Observer onNext() 所在线程为 :main
Observer onComplete() 所在线程为 :main
从上面的例子可以看到:
Observer
(观察者)的onSubscribe()
方法运行在当前线程中。Observable
(被观察者)中的subscribe()
运行在subscribeOn()
指定的线程中。Observer
(观察者)的onNext()
和onComplete()
等方法运行在observeOn()
指定的线程中。
5.2 源码分析
下面我们对线程切换的源码进行一下分析,分为两部分:subscribeOn()
和observeOn()
。
5.2.1 subscribeOn()源码分析
首先来看下subscribeOn()
,我们的例子中是这么个使用的:
.subscribeOn(Schedulers.io())
subscribeOn()
方法要传入一个Scheduler
类对象作为参数,Scheduler
是一个调度类,能够延时或周期性地去执行一个任务。
5.2.1.1 Scheduler类型
通过Schedulers
类我们可以获取到各种Scheduler
的子类。RxJava提供了以下这些线程调度类供我们使用:
Scheduler类型 | 使用方式 | 含义 | 使用场景 |
---|---|---|---|
IoScheduler | Schedulers.io() | io操作线程 | 读写SD卡文件,查询数据库,访问网络等IO密集型操作 |
NewThreadScheduler | Schedulers.newThread() | 创建新线程 | 耗时操作等 |
SingleScheduler | Schedulers.single() | 单例线程 | 只需一个单例线程时 |
ComputationScheduler | Schedulers.computation() | CPU计算操作线程 | 图片压缩取样、xml,json解析等CPU密集型计算 |
TrampolineScheduler | Schedulers.trampoline() | 当前线程 | 需要在当前线程立即执行任务时 |
HandlerScheduler | AndroidSchedulers.mainThread() | Android主线程 | 更新UI等 |
5.2.1.2 Schedulers类的io()
下面我们来看下Schedulers.io()
的代码,其他的Scheduler
子类都差不多,就不逐以分析了,有兴趣的请自行查看哈~
@NonNull
static final Scheduler IO;
@NonNull
public static Scheduler io() {
//1.直接返回一个名为IO的Scheduler对象
return RxJavaPlugins.onIoScheduler(IO);
}
static {
//省略无关代码
//2.IO对象是在静态代码块中实例化的,这里会创建按一个IOTask()
IO = RxJavaPlugins.initIoScheduler(new IOTask());
}
static final class IOTask implements Callable {
@Override
public Scheduler call() throws Exception {
//3.IOTask中会返回一个IoHolder对象
return IoHolder.DEFAULT;
}
}
static final class IoHolder {
//4.IoHolder中会就是new一个IoScheduler对象出来
static final Scheduler DEFAULT = new IoScheduler();
}
可以看到,Schedulers.io()
中使用了静态内部类的方式来创建出了一个单例IoScheduler
对象出来,这个IoScheduler
是继承自Scheduler的。这里mark一发,后面会用到这个IoScheduler
的。
5.2.1.3 Observable类的subscribeOn()
然后,我们就来看下subscribeOn()的代码:
public final Observable subscribeOn(Scheduler scheduler) {
//省略无关代码
return RxJavaPlugins.onAssembly(new ObservableSubscribeOn(this, scheduler));
}
可以看到,首先会将当前的Observable
(其具体实现为ObservableCreate
)包装成一个新的ObservableSubscribeOn
对象。 放个图:
跟前面一样,RxJavaPlugins.onAssembly()
也是将ObservableSubscribeOn
对象原样返回而已,这里就不看了。 可以看下ObservableSubscribeOn
的构造方法:
5.2.1.4 ObservableSubscribeOn类的构造方法
public ObservableSubscribeOn(ObservableSource source, Scheduler scheduler) {
super(source);
this.scheduler = scheduler;
}
也就是把source
和scheduler
这两个保存一下,后面会用到。
然后subscribeOn()
方法就完了。好像也没做什么,就是重新包装一下对象而已,然后将新对象返回。即将一个旧的被观察者包装成一个新的被观察者。
5.2.1.5 ObservableSubscribeOn类的subscribeActual()
接下来我们回到订阅过程,为什么要回到订阅过程呢?因为事件的发送是从订阅过程开始的啊。 虽然我们这里用到了线程切换,但是呢,其订阅过程前面的内容跟上一节分析的是一样的,我们这里就不重复了,直接从不一样的地方开始。还记得订阅过程中Observable
类的subscribeActual()
是个抽象方法吗?因此要看其子类的具体实现。在上一节订阅过程中,其具体实现是在ObservableCreate
类。但是由于我们调用subscribeOn()
之后,ObservableCreate
对象被包装成了一个新的ObservableSubscribeOn
对象了。因此我们就来看看ObservableSubscribeOn
类中的subscribeActual()
方法:
@Override
public void subscribeActual(final Observer<? super T> s) {
final SubscribeOnObserver parent = new SubscribeOnObserver(s);
s.onSubscribe(parent);
parent.setDisposable(scheduler.scheduleDirect(new SubscribeTask(parent)));
}
subscribeActual()
中同样也将我们自定义的Observer
给包装成了一个新的SubscribeOnObserver
对象。同样,放张图:
然后就是调用Observer
的onSubscribe()
方法,可以看到,到目前为止,还没出现过任何线程相关的东西,所以Observer
的onSubscribe()
方法就是运行在当前线程中。 然后我们重点看下最后一行代码,首先创建一个SubscribeTask
对象,然后就是调用scheduler.scheduleDirect()
.。 我们先来看下SubscribeTask
类:
5.2.1.6 SubscribeTask类
//SubscribeTask是ObservableSubscribeOn的内部类
final class SubscribeTask implements Runnable {
private final SubscribeOnObserver parent;
SubscribeTask(SubscribeOnObserver parent) {
this.parent = parent;
}
@Override
public void run() {
//这里的source就是我们自定义的Observable对象,即ObservableCreate
source.subscribe(parent);
}
}
很简单的一个类,就是实现了Runnable
接口,然后run()
中调用Observer.subscribe()
。
5.2.1.7 Scheduler类的scheduleDirect()
再来看下scheduler.scheduleDirect()
方法
public Disposable scheduleDirect(@NonNull Runnable run) {
return scheduleDirect(run, 0L, TimeUnit.NANOSECONDS);
}
往下看:
public Disposable scheduleDirect(@NonNull Runnable run, long delay, @NonNull TimeUnit unit) {
//createWorker()在Scheduler类中是个抽象方法,所以其具体实现在其子类中
//因此这里的createWorker()应当是在IoScheduler中实现的。
//Worker中可以执行Runnable
final Worker w = createWorker();
//实际上decoratedRun还是这个run对象,即SubscribeTask
final Runnable decoratedRun = RxJavaPlugins.onSchedule(run);
//将Runnable和Worker包装成一个DisposeTask
DisposeTask task = new DisposeTask(decoratedRun, w);
//Worker执行这个task
w.schedule(task, delay, unit);
return task;
}
我们来看下创建Worker
和Worker
执行任务的过程。
5.2.1.8 IoScheduler的createWorker()和schedule()
final AtomicReference pool;
public Worker createWorker() {
//就是new一个EventLoopWorker,并且传一个Worker缓存池进去
return new EventLoopWorker(pool.get());
}
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();
//从缓存Worker池中取一个Worker出来
this.threadWorker = pool.get();
}
@NonNull
@Override
public Disposable schedule(@NonNull Runnable action, long delayTime, @NonNull TimeUnit unit) {
//省略无关代码
//Runnable交给threadWorker去执行
return threadWorker.scheduleActual(action, delayTime, unit, tasks);
}
}
注意,不同的Scheduler
类会有不同的Worker
实现,因为Scheduler
类最终是交到Worker
中去执行调度的。
我们来看下Worker
缓存池的操作:
5.2.1.9 CachedWorkerPool的get()
static final class CachedWorkerPool implements Runnable {
ThreadWorker get() {
if (allWorkers.isDisposed()) {
return SHUTDOWN_THREAD_WORKER;
}
while (!expiringWorkerQueue.isEmpty()) {
//如果缓冲池不为空,就从缓存池中取threadWorker
ThreadWorker threadWorker = expiringWorkerQueue.poll();
if (threadWorker != null) {
return threadWorker;
}
}
//如果缓冲池中为空,就创建一个并返回。
ThreadWorker w = new ThreadWorker(threadFactory);
allWorkers.add(w);
return w;
}
}
5.2.1.10 NewThreadWorker的scheduleActual()
我们再来看下threadWorker.scheduleActual()
。 ThreadWorker
类没有实现scheduleActual()
方法,其父类NewThreadWorker
实现了该方法,我们点进去看下:
public class NewThreadWorker extends Scheduler.Worker implements Disposable {
private final ScheduledExecutorService executor;
volatile boolean disposed;
public NewThreadWorker(ThreadFactory threadFactory) {
//构造方法中创建一个ScheduledExecutorService对象,可以通过ScheduledExecutorService来使用线程池
executor = SchedulerPoolFactory.create(threadFactory);
}
public ScheduledRunnable scheduleActual(final Runnable run, long delayTime, @NonNull TimeUnit unit, @Nullable DisposableContainer parent) {
//这里的decoratedRun实际还是run对象
Runnable decoratedRun = RxJavaPlugins.onSchedule(run);
//将decoratedRun包装成一个新对象ScheduledRunnable
ScheduledRunnable sr = new ScheduledRunnable(decoratedRun, parent);
//省略无关代码
if (delayTime <= 0) {
//线程池中立即执行ScheduledRunnable
f = executor.submit((Callable)sr);
} else {
//线程池中延迟执行ScheduledRunnable
f = executor.schedule((Callable)sr, delayTime, unit);
}
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
总结
其实要轻松掌握很简单,要点就两个:
- 找到一套好的视频资料,紧跟大牛梳理好的知识框架进行学习。
- 多练。 (视频优势是互动感强,容易集中注意力)
你不需要是天才,也不需要具备强悍的天赋,只要做到这两点,短期内成功的概率是非常高的。
对于很多初中级Android工程师而言,想要提升技能,往往是自己摸索成长,不成体系的学习效果低效漫长且无助。下面资料部分截图是我花费几个月时间整理的,诚意满满:特别适合有3-5年开发经验的Android程序员们学习。
一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!
AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算
频+大厂面试真题+项目实战源码》]( )收录**
一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!
AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算