RxJava2.x的理解与总结
RxJava的理解与总结
RxJava是一个将观察者模式、迭代器、链式编程、异步结合在一起的开源库。Rx是Reactive Extensions的缩写,翻译过来就是“响应式扩展”,
导入依赖
implementation 'io.reactivex.rxjava3:rxjava:3.0.4'
implementation 'io.reactivex.rxjava3:rxandroid:3.0.0'
在介绍RxJava前,先来段基础使用示例代码:
//被观察者
Observable.create(object : ObservableOnSubscribe<String> {
override fun subscribe(emitter: ObservableEmitter<String>) {
emitter.onNext("1")
emitter.onNext("2")
emitter.onNext("3")
emitter.onComplete()
emitter.onComplete()
println("create-Looper:" + (Looper.getMainLooper() == Looper.myLooper()))
}
}).subscribeOn(Schedulers.io())//被观察者执行在什么线程线程
.observeOn(AndroidSchedulers.mainThread())//观察者执行在什么线程线程
//建立订阅关系
.subscribe(object : Observer<String> {//实现观察者接口
override fun onSubscribe(d: Disposable) {
println("onSubscribe-Looper:" + (Looper.getMainLooper() == Looper.myLooper()))
}
override fun onNext(s: String) {
println("onNext$s")
}
override fun onError(e: Throwable) {
println("onError")
}
override fun onComplete() {
println("onComplete")
}
})
Observable
Observable
中文意思就是被观察者,在create(ObservableOnSubscribe<T> source)
方法中,会先对传入的参数判空,如果为空,将直接抛出空指针异常,接下来会尝试创建Observable
抽象类的实例ObservableCreate
。
create(ObservableOnSubscribe<T> source)
方法的参数是ObservableOnSubscribe<T>
,可以理解为一个计划表,泛型T是要操作对象的类型,重写subscribe方法。然后在其中写准备完成的事情(任务),当你执行这些任务的时候,订阅了这个对象的观察者就会收到消息。
然后subscribe有一个传参,他有3个方法,分别是onNext();onError();onComplete();
。
其中onNext();
可以多次调用,Observer都能收到。onComplete();
可以多次调用,但Observer只接受一次;onError();
只能调用一次,第二次将出现异常。
Observer
通过new创建一个Observer并实现其中的方法:onNext();onError();onComplete();
。看到这3个方法,就能猜到是做什么的了。
如上面所说,当Observable通过subscribe的传参执行onNext()
等方法时,Observer的这些方法就会被执行。
这个关系就像音乐软件的歌手、音乐人,和关注他们的听众,当音乐人发布新歌时,听众就会收到通知。
Observer
这个对象是怎么接收到消息的呢?
这里可以看一看RxJava的源码实现。
- 先从
Observable
的create()
方法开始,上面说了,这个方法里面创建并返回了一个ObservableCreate
对象。然后这个类的构造函数有一个传参,就是ObservableOnSubscribe
接口。 - 接下来继续看
subscribe()
方法的实现,这个方法有一个Observer
接口传参,它用于和Observable
建立订阅关系。在方法内会对observer的实例进行空判断,然后执行subscribeActual()
方法并传入Observer
实例,这个方法在Observable
中是一个抽象的方法,其具体实现在ObservableCreate
类中 - 在
subscribeActual()
方法中,会使用传入的参数创建CreateEmitter
类,然后调用observer.onSubscribe()
通知开发者订阅关系已经建立。接着在try catch 中调用source.subscribe(parent)
。这里source就是ObservableCreate
构造函数中传入的ObservableOnSubscribe
接口实例,然后parent就是CreateEmitter
类了。 - 在
CreateEmitter
类中实现了onNext();onError();onComplete();
等方法,每当Observable
调用这些方法时,CreateEmitter
会调用Observer
对应的方法。
为什么 onComplete() 只能接收一次?
看CreateEmitter#onComplete()
的实现:
@Override
public void onComplete() {
if (!isDisposed()) {//判断该订阅关系是否已经结束(失效),当isDisposed()返回true表示订阅关系已经失效
try {
observer.onComplete(); //调用observer的onComplete()
} finally {
dispose(); //结束订阅关系
}
}
}
在上面的代码中,当调用了onComplete()
后,执行了dispose()
结束订阅
为什么 onError() 只能调用一次?
我们看看onError()
的实现:
@Override
public void onError(Throwable t) {
//在tryOnError()方法内尝试调用onError(),当返回true时代表调用成功
//如果之前调用过tryOnError(),这里会返回false
if (!tryOnError(t)) {
RxJavaPlugins.onError(t);
}
}
@Override
public boolean tryOnError(Throwable t) {
if (t == null) {
t = new NullPointerException("onError called with null. Null values are generally not allowed in 2.x operators and sources.");
}
if (!isDisposed()) {
try {
//isDisposed()返回false代表该订阅还有效,调用onError()
observer.onError(t);
} finally {
//结束订阅关系
dispose();
}
return true;
}
return false;
}
Scheduler
RxJava是支持异步的,但要如何做到呢?这就需要讲到Scheduler,中文翻译过来就是调度器。
它是用来控制线程的,如果没有设置Scheduler,RxJava遵循哪个线程产生,就在哪个线程消费的原则,即观察者和消费者是在同一个线程。
Scheduler简单使用
前台刷新UI,后台完成任务。
Observable.create(object : ObservableOnSubscribe<String> {
//...
}).subscribeOn(Schedulers.io())//被观察者执行在什么线程线程
.observeOn(AndroidSchedulers.mainThread())//观察者执行在什么线程线程
//建立订阅关系
.subscribe(object : Observer<String> {
//...
})
在上面这个例子中,设置Schedulers用到了subscribeOn();
和observeOn()
两个方法。
subscribeOn(Schedulers.io())
:被观察者执行在什么线程线程observeOn(AndroidSchedulers.mainThread())
:表示观察者执行在什么线程
查看subscribeOn()
实现,发现这个方法只做了一件事,就是创建并返回了ObservableSubscribeOn
类。
public final Observable<T> subscribeOn(Scheduler scheduler) {
ObjectHelper.requireNonNull(scheduler, "scheduler is null");
return RxJavaPlugins.onAssembly(new ObservableSubscribeOn<T>(this, scheduler));
}
ObservableSubscribeOn构造函数有两个参数,分别是:
ObservableSource
接口Scheduler
对象。
因为这里返回了ObservableSubscribeOn,所以最中调用subscribe()
方法的就不再是ObservableCreate
了,这里要注意!
但ObservableSubscribeOn和ObservableCreate的实现其实差不多,只是多了一个线程切换的操作。
public final class ObservableSubscribeOn<T> extends AbstractObservableWithUpstream<T, T> {
//通过构造方法传入的
public ObservableSubscribeOn(ObservableSource<T> source, Scheduler scheduler) {
//构造方法传入`source`的实际上是`ObservableCreate`对象,他继承了`Observable`,而`Observable`这个抽象类实现了`ObservableSource`接口。
super(source);
//Scheduler是一个抽象的类,这里传入的是这个类的实例。比如 Schedulers.io() 传入的是 IoScheduler
//在Schedulers中会继续讲解这个实例是怎么得到的,注意!Scheduler 和 Schedulers 不是同一个类!
this.scheduler = scheduler;
}
@Override
public void subscribeActual(final Observer<? super T> observer) {
//一个Observer接口实例,和CreateEmitter类作用一样
//每当`Observable`调用onNext()……这些方法时,`SubscribeOnObserver`会调用`Observer`对应的方法。
final SubscribeOnObserver<T> parent = new SubscribeOnObserver<T>(observer);
observer.onSubscribe(parent); //通知开发者订阅关系已经建立
//scheduler.scheduleDirect()是线程切换的关键方法
parent.setDisposable(scheduler.scheduleDirect(new SubscribeTask(parent)));
}
final class SubscribeTask implements Runnable {
private final SubscribeOnObserver<T> parent;
SubscribeTask(SubscribeOnObserver<T> parent) {
this.parent = parent;
}
@Override
public void run() {
//使用ObservableCreated对象调用 subscribe()
source.subscribe(parent);
}
}
//...
}
Schedulers
Schedulers类; 注意!Scheduler和Schedulers不是同一个类!
它是一个Scheduler抽象类的实例工厂,这个类通过单例模式生成各种环境下的Scheduler实例
//开发者通过调用其内部的静态方法来获取Scheduler实例
//如:
Schedulers.io()
Schedulers.newThread()
Schedulers.single()
接下来让我们看看其具体实现:
public final class Schedulers {
//在静态代码块中,RxJava初始化了多个场景的Task,然后在这些Task的call方法中返回其对应场景的Scheduler实例
static {
SINGLE = RxJavaPlugins.initSingleScheduler(new SingleTask());
COMPUTATION = RxJavaPlugins.initComputationScheduler(new ComputationTask());
//这里`initIoScheduler()`传入的参数是Scheduler.IOTask对象,在内部会调用call();然后返回Scheduler这个抽象类的实例IoScheduler
IO = RxJavaPlugins.initIoScheduler(new IOTask());
TRAMPOLINE = TrampolineScheduler.instance();
NEW_THREAD = RxJavaPlugins.initNewThreadScheduler(new NewThreadTask());
}
//...
//Schedulers.io()
public static Scheduler io() {
//RxJavaPlugins是钩子函数,后面的RxJavaPlugins篇再单独讲解
//实际上这里最终返回的就是`IO`,`IO`是Scheduler类中的一个静态类
return RxJavaPlugins.onIoScheduler(IO);
}
}
//...
//Task实现,上面静态代码块中初始化的Task类都实现了Callable接口
//Callable接口在FutureTask中有介绍
static final class IOTask implements Callable<Scheduler> {
@Override
public Scheduler call() throws Exception {
return IoHolder.DEFAULT;
}
}
static final class NewThreadTask implements Callable<Scheduler> {
@Override
public Scheduler call() throws Exception {
return NewThreadHolder.DEFAULT;
}
}
Schedulers在静态代码块中创建了对应场景的Task,然后Task实现了Callable
接口。然后通过调用call()
方法得到对应场景的Scheduler实例。
因此上面的subscribeOn()
方法和ObservableSubscribeOn
构造方法传入的就是一个Scheduler实例。
scheduleDirect()
知道了Scheduler实例创建过程,那么让我们回到Scheduler类。
scheduleDirect()
就是刚刚说的线程切换的关键方法。
scheduleDirect()
是怎么被调用的呢?
Observable调用subscribeOn(Scheduler)
时,内部会创建一个ObservableSubscribeOn
类,然后其中的subscribeActual()
执行了scheduleDirect()
。
@Override
public void subscribeActual(final Observer<? super T> observer) {
final SubscribeOnObserver<T> parent = new SubscribeOnObserver<T>(observer);
observer.onSubscribe(parent);
parent.setDisposable(scheduler.scheduleDirect(new SubscribeTask(parent)));
}
//下面是scheduleDirect()具体实现:
public abstract class Scheduler {
//...
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()
方法,这个方法是抽象的,它的具体实现是在Scheduler的子类。
中间创建了一个Task包装Runnable,关键是w.schedule(task, delay, unit)
这行代码,这行代码是执行了线程的关键。
w.schedule()
这个方法是抽象的,它的具体实现在Scheduler的子类的一个内部类。
比如:IoScheduler
实现了createWorker()
方法,并返回了其内部类EventLoopWorker
。
static final class EventLoopWorker extends Scheduler.Worker implements Runnable {
//...
public Disposable schedule(@NonNull Runnable action, long delayTime, @NonNull TimeUnit unit) {
//...
return threadWorker.scheduleActual(action, delayTime, unit, tasks);
}
//...
}
public class NewThreadWorker extends Scheduler.Worker implements Disposable {
public ScheduledRunnable scheduleActual(final Runnable run, long delayTime, @NonNull TimeUnit unit, @Nullable DisposableContainer parent) {
Future<?> f;
try {
if (delayTime <= 0) {
//将Runnable提交到线程池执行
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;
}
}
每个Scheduler的实例都有自己的线程池,当传入一个Runnable时,其中的任务将按序放到线程池中进行处理。
这就是RxJava可以做到切换线程的原因
通过查看GitHub开源项目的简介开源知道,RxJava有几个基类。
他们分别适用于不同的场景
io.reactivex.rxjava3.core.Flowable
io.reactivex.rxjava3.core.Observable
io.reactivex.rxjava3.core.Single
io.reactivex.rxjava3.core.Completable
io.reactivex.rxjava3.core.Maybe