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的源码实现。

  1. 先从Observablecreate()方法开始,上面说了,这个方法里面创建并返回了一个ObservableCreate对象。然后这个类的构造函数有一个传参,就是ObservableOnSubscribe接口。
  2. 接下来继续看subscribe()方法的实现,这个方法有一个Observer接口传参,它用于和Observable建立订阅关系。在方法内会对observer的实例进行空判断,然后执行subscribeActual()方法并传入Observer实例,这个方法在Observable中是一个抽象的方法,其具体实现在ObservableCreate类中
  3. subscribeActual()方法中,会使用传入的参数创建CreateEmitter类,然后调用observer.onSubscribe()通知开发者订阅关系已经建立。接着在try catch 中调用source.subscribe(parent)。这里source就是ObservableCreate构造函数中传入的ObservableOnSubscribe接口实例,然后parent就是CreateEmitter类了。
  4. 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()两个方法。

  1. subscribeOn(Schedulers.io()):被观察者执行在什么线程线程
  2. 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构造函数有两个参数,分别是:

  1. ObservableSource接口
  2. 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有几个基类。
他们分别适用于不同的场景

  1. io.reactivex.rxjava3.core.Flowable
  2. io.reactivex.rxjava3.core.Observable
  3. io.reactivex.rxjava3.core.Single
  4. io.reactivex.rxjava3.core.Completable
  5. io.reactivex.rxjava3.core.Maybe

参考文章

  1. https://www.jianshu.com/p/cd3557b1a474
  2. https://blog.csdn.net/yang_study_first/article/details/111085666
  3. RxjavaPlugins
  4. RxjavaPlugins-Github
posted @ 2023-01-30 19:50  Ysun_top  阅读(109)  评论(0编辑  收藏  举报