深入理解RxJava设计原理

222 阅读5分钟

背景

RxJava是一个在Android开发中广泛使用的响应式编程库,它提供了强大的工具和模式来处理异步事件流。然而,RxJava的强大功能和灵活性往往会导致一些开发者陷入误区。有些开发者可能会过度使用,将其应用于不适合的场景,导致代码变得复杂难懂。此外,错误的使用方式可能会导致性能问题和内存泄漏等。因此,我们需要深入阅读源码并理解其原理。

基本组件

RxJava 的核心原理其实非常简单。可类比观察者模式。Observable是被观察者,作为数据源产生数据。Observer是观察者,消费上游的数据源。

每个Observable可注册多个Observer。但是默认情况下,每当有注册发生时,Observable的生产方法subscribe都会被调用。如果想只生产一次,可以调用Observable.cached方法。

被观察者Observable还有多个变体,如Single、Flowable。Single代表只产生一个元素的数据源。Flowable是支持背压的数据源。通过背压设计,下游监听者可以向上游反馈信息,可以达到控制发送速率的功能。

Observable和Observer是通过装饰器模式层层包装达到从而串联起来。转换API如map等,会创建一个新的ObservableMap基层自Observable,包装原始的Observable作为source,而在真正执行时,先做转换操作,再发给下游的观察者。

Scheduler是RxJava为多线程执行提供的支持类,它将可以将生产者或者消费者的执行逻辑包装成一个Worker,提交到框架提供的公共线程池中,如Schedulers.io()、Schedulers.newThread()等。便于理解,可以将Schedulers类比做线程池,Worker类比做线程池中的线程。可以通过 Observable.subscribeOn和Observable.observeOn分别制定被观察者和观察者执行的线程,来达到异步非阻塞。

RxJava 核心架构图如下:

小米办公20230712-111943.jpg

基本原理

RxJava 的代码,观察者模式和装饰器模式。为了便于理解核心原理,我们写了几个简版的Rxjava框架类。

// 返回的子类是ObservableCreate

Observable<String> observable = Observable.create(new ObservableOnSubscribe<String>() {

    @Override
    public void subscribe(ObservableEmitter<String> emitter) throws Exception {
        emitter.onNext("test");
        emitter.onComplete();
    }
});

// 订阅observable
observable.subscribe(new Observer<String>() {

    @Override
    public void onSubscribe(Disposable d) {
        System.out.println(Thread.currentThread().getName() + " , onSubscribe");
    }

    @Override
    public void onNext(String s) {
        System.out.println(Thread.currentThread().getName() + " ,s = " + s);
    }

    @Override
    public void onError(Throwable e) {}

    @Override
    public void onComplete() {
        System.out.println(Thread.currentThread().getName() + " , onComplete");
    }

});

Observable--被观察者的核心抽象类

public abstract class Observable<T> implements ObservableSource<T> {

    @Override
    public void subscribe(Observer<T> observer) {
        // 和谁建立订阅?
        // 怎么建立订阅?
        // 为了保证拓展性,交给具体的开发人员实现。这里提供一个抽象的方法
        subscribeActual(observer);
    }

    protected abstract void subscribeActual(Observer<T> observer);

    public static <T> Observable<T> create(ObservableOnSubscribe<T> source) {
        return new ObservableCreate<>(source);
    }

    public ObservableSubscribeOn<T> subscribeOn(Scheduler scheduler) {
        return new ObservableSubscribeOn<>(this, scheduler);
    }

    public ObservableObserveOn<T> observeOn(Scheduler scheduler) {
        return new ObservableObserveOn<>(this, scheduler);
    }
}

Observable是一个抽象类,定义了subscribe这个final方法,最终会调用 subscribeActual(observer);而subscribeActual是由子类实现的方法,自然我们需要看ObserverableCreate内部的具体实现。 ObservableCreate

public class ObservableCreate<T> extends Observable<T> {
    final ObservableOnSubscribe<T> source;

    public ObservableCreate(ObservableOnSubscribe<T> source) {
        this.source = source;
    }

    @Override
    protected void subscribeActual(Observer<T> observer) {
        CreateEmitter<T> emitter = new CreateEmitter<T>(observer);
        observer.onSubscribe();
        source.subscribe(emitter);
    }

    static class CreateEmitter<T> implements Emitter<T> {
        Observer<T> observer;
        boolean done;

        public CreateEmitter(Observer<T> observer) {
            this.observer = observer;
        }

        @Override
        public void onNext(T t) {
            if (done) return;
            observer.onNext(t);
        }

        @Override
        public void onError(Throwable throwable) {
            if (done) return;
            observer.onError(throwable);
            done = true;
        }

        @Override
        public void onComplete() {
            if (done) return;
            observer.onComplete();
            done = true;
        }
    }
}

ObserverableCreate,它包装了一个source对象,即传入的ObserverableOnSubscribe。

    @Override
    protected void subscribeActual(Observer<T> observer) {
        CreateEmitter<T> emitter = new CreateEmitter<T>(observer);
        observer.onSubscribe();
        source.subscribe(emitter);
    }
  1. 将观察者observer包装到一个CreateEmitter里。
  2. 调用observer的onSubscribe方法。
  3. 调用source(即生产代码接口)的subscribe方法,传入这个emitter。

第二步中,直接调用了我们写的消费者的onSubscribe方法,很好理解,即创建订阅关系的回调方法。重点在第三步,source.subscribe(parent);这个parent是包装了observer的emitter。还记得source就是我们写的发送事件的代码。其中手动调用了emitter.onNext()来发送数据。那么我们CreateEmitter.onNext()做了什么?

    @Override
    public void onNext(T t) {
        if (done) return;
        observer.onNext(t);
    }

done对应源码的!isDisposed(),判断订阅关系。observer.onNext(t)这个observer就是我们写的消费者。以上就是RxJava最基本的原理,其实逻辑很简单,就是在创建订阅关系的时候,直接调用生产逻辑代码,然后再生产逻辑的onNext中,调用了观察者observer.onNext。

线程调度

理解了上面的调用逻辑,很自然可以明白。subscribeOn通过层层包装,最终的实现是ObservableSubscribeOn,observeOn最终的实现是ObservableObserveOn。类似的,我们来看下内部的具体实现,我们以ObservableObserveOn为例,便于理解,依然是简版的Rxjava框架类。

...
.subscribeOn(Schedulers.io())// 主要来决定我执行subscribe方法所处的线程,也就是产生事件发射事件所在的线程
.observeOn(AndroidSchedulers.mainThread())// 来决定下游事件被处理时所处的线程
...

ObservableObserveOn--调度下游的执行的线程

public class ObservableObserveOn<T> extends AbstractObservableWithUpStream<T, T> {

    final Scheduler scheduler;
    public ObservableObserveOn(ObservableSource<T> source, Scheduler scheduler) {
        super(source);
        this.scheduler = scheduler;
    }

    @Override
    protected void subscribeActual(Observer<T> observer) {
        Scheduler.Worker worker = scheduler.createWorker();
        source.subscribe(new ObserveOnObserver<>(observer, worker));
    }

    static final class ObserveOnObserver<T> implements Observer<T>, Runnable {
        final Observer<T> downSteam;
        final Scheduler.Worker worker;
        final Deque<T> queue;

        volatile boolean done;
        volatile Throwable error;
        volatile boolean over;

        public ObserveOnObserver(Observer<T> downSteam, Scheduler.Worker worker) {
            this.downSteam = downSteam;
            this.worker = worker;
            queue = new ArrayDeque<>();
        }

        @Override
        public void onSubscribe() {
            downSteam.onSubscribe();
        }

        @Override
        public void onNext(T t) {
            queue.offer(t);// 把事件加入队列,offer不抛异常,只会返回false
            schedule();
        }

        private void schedule() {
            worker.schedule(this);
        }

        @Override
        public void onComplete() {}

        @Override
        public void onError(Throwable throwable) {}

        @Override
        public void run() {
            drainNormal();
        }
        /**
         * 从队列中排放事件并处理
        */
         private void drainNormal() {
                final Deque<T> q = queue;
                final Observer<T> a = downSteam;

                while (true) {
                    boolean d = done;
                    T t = q.poll();// 取出数据,没有数据的时候不会抛异常,返回null
                    boolean empty = t == null;
                    if (checkTerminated(d, empty, a)) {
                        return;
                    }

                    if (empty) {
                        break;
                    }

                    a.onNext(t);
                }
        }

        private boolean checkTerminated(boolean d, boolean empty, Observer<T> a) {
            if (over) {
                queue.clear();
                return true;
            }

            if (d) {
                Throwable e = error;
                if (e != null) {
                    over = true;
                    a.onError(error);
                    return true;
                } else if (empty) {
                    over = true;
                    a.onComplete();
                    return true;
                }
            }
            return false;
        }
    }
}
  1. 最终生产者代码中调用onNext时,会调用schedule方法。
  2. schedule方法中,会提交自身(ObserveOnObserver)到线程池。
  3. 而run方法会调用onNext(emitter)。

可见,RxJava 线程调度的机制就是通过observeOn(Scheduler)将发送元素的代码onNext(emitter)提交到线程池里执行。