【RxJava】RxJava入门和原理分析

学而不思则罔,思而不学则殆

【RxJava】RxJava入门和原理分析

  • 引言
  • RxJava接口介绍
  • RxJava简单范例
    • just操作符使用
    • just操作符解析
  • 数据源+数据处理
    • 双向链表调用链


引言

我相信很多人初学RxJava的时候一定被里面的各种接口和回调绕晕了,各种回调,各种订阅,我在哪儿,我又在哪儿,因为博主就是,最开始学习的时候被绕晕了。所以本篇文章就带领读者从一种熟悉的逻辑结构中来学习和了解RxJava—双向链表。

个人理解:RxJava 是 一种链式调用链,原理是双向链表调用链+代理模式
首先什么是链式调用,常见的是就Builder(构建者模式)的用法,比如OkHttp中的Client构造:

        OkHttpClient client = new OkHttpClient().newBuilder()
                .connectTimeout(10, TimeUnit.SECONDS)
                .writeTimeout(30, TimeUnit.SECONDS)
                .readTimeout(10, TimeUnit.SECONDS)
                .build();

还比如Kotlin中:

fun main() {
    //统计文件中字符出现的个数
    File("MyKotlinWorld.iml")
        .readText()
        .toCharArray()
        .filterNot(Char::isWhitespace)
        .groupBy { it }
        .map { it.key to it.value.count() }
        .forEach(::println)
}

在RxJava中能够链式调用的关键元素时接口ObservableSource,所有的数据源或者数据处理都实现或者间接实现了该接口。

RxJava接口介绍

我相信很多小伙伴第一次学习RxJava的时候都会被该框架中的名词接口给绕晕。RxJava中使用的接口非常多,很多都会把人给绕晕,博主第一次看的时候很多接口都不是很理解。先来看一下RxJava中的接口
【RxJava】RxJava入门和原理分析_第1张图片
别看这么多接口,我们不都分析,作为入门篇介绍,我们只来介绍分析一下这三个接口。

接口 说明
ObservableSource 被观察者和订阅关系的实现
Observer 观察者
Disposable 中断观察的桥梁

RxJava简单范例

just操作符使用

        @NonNull Observable<Integer> observable = Observable.just(1, 2, 3, 4);
        System.out.println("observable:" + observable);
        //2.建立观察者
        Observer<Integer> observer = new Observer<Integer>() {
            @Override
            public void onSubscribe(@NonNull Disposable d) {
                System.out.println("onSubscribe:" + d);
                // FIXME: 2020/11/11 如果想取消可以调用d.dispose(); 打断
            }

            @Override
            public void onNext(@NonNull Integer integer) {
                System.out.println("onNext:" + integer);
            }

            @Override
            public void onError(@NonNull Throwable e) {
                System.out.println("onError:" + e);
            }

            @Override
            public void onComplete() {
                System.out.println("onComplete");
            }
        };
        //3.建立订阅关系
        observable.subscribe(observer);

一般都是链式调用,用法如下:

    private static void test2() {
        Observable.just(1, 2, 3, 4).subscribe(new Observer<Integer>() {
            @Override
            public void onSubscribe(@NonNull Disposable d) {
                System.out.println("onSubscribe:" + d);
                // FIXME: 2020/11/11 如果想取消可以调用d.dispose(); 打断
            }

            @Override
            public void onNext(@NonNull Integer integer) {
                System.out.println("onNext:" + integer);
            }

            @Override
            public void onError(@NonNull Throwable e) {
                System.out.println("onError:" + e);
            }

            @Override
            public void onComplete() {
                System.out.println("onComplete");
            }
        });
    }

结果如下:

observable:io.reactivex.rxjava3.internal.operators.observable.ObservableFromArray@42a57993
onSubscribe:io.reactivex.rxjava3.internal.operators.observable.ObservableFromArray$FromArrayDisposable@75b84c92
onNext:1
onNext:2
onNext:3
onNext:4
onComplete

我们来看一下建立订阅关系的subscribe方法。

    //Observable.java
    @Override
    public final void subscribe(@NonNull Observer<? super T> observer) {
        //判空
        Objects.requireNonNull(observer, "observer is null");
        try {
            //转换处理
            observer = RxJavaPlugins.onSubscribe(this, observer);
            //判空
            Objects.requireNonNull(observer, "The RxJavaPlugins.onSubscribe hook returned a null Observer. Please change the handler provided to RxJavaPlugins.setOnObservableSubscribe for invalid null returns. Further reading: https://github.com/ReactiveX/RxJava/wiki/Plugins");
            //实际订阅处理逻辑
            subscribeActual(observer);
        } catch (NullPointerException e) { // NOPMD
            throw e;
        } catch (Throwable e) {
           ...
        }
    }
    
    protected abstract void subscribeActual(@NonNull Observer<? super T> observer);

订阅的主要逻辑是在subscribeActual方法中实现的,该方法是一个抽象方法。具体的实现是在不同的被观察者实现的。
这个方法很重要,是重点
我们就刚刚测试的just操作符来看一下subscribeActual的实现。

just操作符解析

    //Observable.java
    public static <T> Observable<T> just(@NonNull T item1, @NonNull T item2, @NonNull T item3, @NonNull T item4) {
        Objects.requireNonNull(item1, "item1 is null");
        Objects.requireNonNull(item2, "item2 is null");
        Objects.requireNonNull(item3, "item3 is null");
        Objects.requireNonNull(item4, "item4 is null");

        return fromArray(item1, item2, item3, item4);
    }
    
    public static <T> Observable<T> fromArray(@NonNull T... items) {
        Objects.requireNonNull(items, "items is null");
        if (items.length == 0) {
            return empty();
        }
        if (items.length == 1) {
            return just(items[0]);
        }
        return RxJavaPlugins.onAssembly(new ObservableFromArray<>(items));
    }

just操作最终会生成ObservableFromArray的对象,该类传入一个泛型数组。
看一下ObservableFromArray的源码,ObservableFromArray实现了subscribeActual方法。

public final class ObservableFromArray<T> extends Observable<T> {
    final T[] array;
    public ObservableFromArray(T[] array) {
        this.array = array;
    }

    @Override
    public void subscribeActual(Observer<? super T> observer) {
        FromArrayDisposable<T> d = new FromArrayDisposable<>(observer, array);

        observer.onSubscribe(d);

        if (d.fusionMode) {
            return;
        }

        d.run();
    }
    ...
}

当我们通过subscribe注册的时候,走到了subscribeActual方法。其中observer就是我们建立订阅关系时候实现的观察者对象。该对象被用来实例化一个新的FromArrayDisposable对象d,然后调用了FromArrayDisposable的run方法。看一下FromArrayDisposable类源码,忽略其中一些方法,只看主逻辑:

    static final class FromArrayDisposable<T> extends BasicQueueDisposable<T> {

        final Observer<? super T> downstream;

        final T[] array;
        ...
        FromArrayDisposable(Observer<? super T> actual, T[] array) {
            this.downstream = actual;
            this.array = array;
        }
        ...
        void run() {
            T[] a = array;
            int n = a.length;

            for (int i = 0; i < n && !isDisposed(); i++) {
                T value = a[i];
                if (value == null) {
                    downstream.onError(new NullPointerException("The element at index " + i + " is null"));
                    return;
                }
                downstream.onNext(value);
            }
            if (!isDisposed()) {
                downstream.onComplete();
            }
        }
    }

该run方法很简单,for循环把之前传入的数组一个一个分发出去。时序图如下:
【RxJava】RxJava入门和原理分析_第2张图片

数据源+数据处理

RxJava中的Observable有很多静态方法和非静态方法。

静态方法一般可以作为数据源,做为头部节点
非静态方法一般可以做为中间数据处理,做为中间节点

我们看几个非静态方法。

    public final <U extends Collection<? super T>> Observable<U> buffer(int count, int skip, @NonNull Supplier<U> bufferSupplier) {
        ObjectHelper.verifyPositive(count, "count");
        ObjectHelper.verifyPositive(skip, "skip");
        Objects.requireNonNull(bufferSupplier, "bufferSupplier is null");
        return RxJavaPlugins.onAssembly(new ObservableBuffer<>(this, count, skip, bufferSupplier));
    }
    
    public final Observable<T> sample(long period, @NonNull TimeUnit unit, @NonNull Scheduler scheduler) {
        Objects.requireNonNull(unit, "unit is null");
        Objects.requireNonNull(scheduler, "scheduler is null");
        return RxJavaPlugins.onAssembly(new ObservableSampleTimed<>(this, period, unit, scheduler, false));
    }
    
    public final Observable<T> scan(@NonNull BiFunction<T, T, T> accumulator) {
        Objects.requireNonNull(accumulator, "accumulator is null");
        return RxJavaPlugins.onAssembly(new ObservableScan<>(this, accumulator));
    }

这几个Observable具体是干什么的我们先不管,就是他们都有一个共同点,就是都传入了一个this对象。这种情况感觉就像是套娃,我自己是一个Observable,但是呢,我自己还持有了一个Observable。
测试一个简单的链式调用,先通过just操作符发送4…9,在通过操作符startWithArray在4…9前面发送1,2,3。然后在通过map操作符进行对象转换成String类型。

    private static void test() {
        @NonNull Observable<Integer> observable0 = Observable.just(4, 5, 6, 7, 8, 9);
        @NonNull Observable<Integer> observable1 = observable0.startWithArray(1, 2, 3);
        @NonNull Observable<String> observable2 = observable1.map(new Function<Integer, String>() {
            @Override
            public String apply(Integer integer) throws Throwable {
                StringBuilder stringBuilder = new StringBuilder("" + integer).append(":");
                for (Integer i = 0; i < integer; i++) {
                    stringBuilder.append("a");
                }
                return stringBuilder.toString();
            }
        });
        System.out.println("observable0:" + observable0);
        System.out.println("observable1:" + observable1);
        System.out.println("observable2:" + observable2);
        observable2
                .subscribe(new Observer<String>() {
                    @Override
                    public void onSubscribe(@NonNull Disposable d) {
                        System.out.println("onSubscribe:" + d);
                        // FIXME: 2020/11/11 如果想取消可以调用d.dispose(); 打断
                    }

                    @Override
                    public void onNext(@NonNull String integer) {
                        System.out.println("onNext:" + integer);
                    }

                    @Override
                    public void onError(@NonNull Throwable e) {
                        System.out.println("onError:" + e);
                    }

                    @Override
                    public void onComplete() {
                        System.out.println("onComplete");
                    }
                });
    }

测试结果如下:

observable0:io.reactivex.rxjava3.internal.operators.observable.ObservableFromArray@6bc7c054
observable1:io.reactivex.rxjava3.internal.operators.observable.ObservableConcatMap@232204a1
observable2:io.reactivex.rxjava3.internal.operators.observable.ObservableMap@4aa298b7
onSubscribe:io.reactivex.rxjava3.internal.operators.observable.ObservableMap$MapObserver@28d93b30
onNext:1:a
onNext:2:aa
onNext:3:aaa
onNext:4:aaaa
onNext:5:aaaaa
onNext:6:aaaaaa
onNext:7:aaaaaaa
onNext:8:aaaaaaaa
onNext:9:aaaaaaaaa
onComplete

这整个流程在我的理解下,可以比喻成一个双向链表。其中每个操作符对应的Observable对象可以理解为双向链表中的每个节点Node.通过log信息我们知道共有三个Observable。分别是ObservableMap,ObservableConcatMap和ObservableFromArray。其中ObservableFromArray我理解是数据发射源(链表头),当我们在最外层ObservableMap(链表尾)调用subscribe注册建立订阅关系时,调用了ObservableMap实现了subscribeActual的方法。可以看到该方法内部通过source再去注册。在这个例子中此时source是ObservableConcatMap对象。

public final class ObservableMap<T, U> extends AbstractObservableWithUpstream<T, U> {
    protected final ObservableSource<T> source;
    ...
    @Override
    public void subscribeActual(Observer<? super U> t) {
        source.subscribe(new MapObserver<T, U>(t, function));
    }
    ...
 }

再来看ObservableConcatMap类的subscribeActual方法,忽略掉暂时不关系的代码,可以看到这里也是调用subscribe再一次进行注册,那个时候的source对象是ObservableFromArray的实例。

public final class ObservableConcatMap<T, U> extends AbstractObservableWithUpstream<T, U> {
    ...
    @Override
    public void subscribeActual(Observer<? super U> observer) {
        ...
        if (delayErrors == ErrorMode.IMMEDIATE) {
            SerializedObserver<U> serial = new SerializedObserver<>(observer);
            source.subscribe(new SourceObserver<>(serial, mapper, bufferSize));
        } else {
            source.subscribe(new ConcatMapDelayErrorObserver<>(observer, mapper, bufferSize, delayErrors == ErrorMode.END));
        }
    }
    ...
 }

其中ObservableFromArray的subscribeActual方法在前面已经分析过了。其中这里就都走到的链式调用的(链表头部)。接下载就是一步一步数据返回的操作的。数据从链表头部返回到链表尾部。整个注册的过程是不是就像一个套娃,一个接着一个的注册,理论上这个双向链表有多长就会注册多少个,没有上限的,可以根据业务来调整。但是一般的开发中4-5个节点已经算个比较多的,就算加上线程切换的两个节点。


上述过程中不知道大家有没有发现设计模式的影子。当我们通过ObservableMap注册时候,并不是ObservableMap直接处理的,而是通过ObservableConcatMap,ObservableConcatMap也是同理,是通过ObservableFromArray来处理,这种我理解为是一种【代理模式】,代理模式介绍可以访问【设计模式】代理模式(Proxy Pattern)。

其中Observer也是,我们最开始注册的时候的Observer被MapObserver持有
而ObservableMap又通过MapObserver实例对象去建立订阅关系;
在ObservableConcatMap中MapObserver实例对象有被SourceObserver或者ConcatMapDelayErrorObserver持有,ObservableConcatMap中又通过SourceObserver或者ConcatMapDelayErrorObserver去建立订阅关系

这一层一层的关系也是一种代理模式

双向链表调用链

可以理解为每个节点Node,都持有上一个节点的Observable,头结点除外,并且持有下一个节点的Observer,尾结点除外。
可以理解为每个节点Node,都持有上一个节点的Observable,头结点除外,并且持有下一个节点的Observer,尾结点除外。
可以理解为每个节点Node,都持有上一个节点的Observable,头结点除外,并且持有下一个节点的Observer,尾结点除外。

我觉的这句话很重要说三遍,希望读者可以多品一品。
【RxJava】RxJava入门和原理分析_第3张图片
根据上面的demo,画了一个逻辑结构图,注册的时候是从:

ObservableFromArray <-- ObservableConcatMap <-- ObservableMap

观察者的回调是从:

ConcatMapDelayErrorObserver --> MapObserver --> DiyObserver

综上所述,是RxJava大概的逻辑结构,至于读者想要了解每一个具体的操作符怎么实现的,具体原理,可以在此基础上,对没有双向链表中的节点做具体的分析。当然本人也会去分析他们,有机会分享不同的操作符具体的实现。
大家共同成长,加油,打工人!!!
大家共同成长,加油,打工人!!!
大家共同成长,加油,打工人!!!

你可能感兴趣的:(RxJava,Java,RxJava)