从RxJava1.x到2.0

1.概述

关于RxJava2.0与1.x区别的详细介绍,参考官方文章:https://github.com/ReactiveX/RxJava/wiki/What%27s-different-in-2.0

当被观察者发出事件的速度快于观察者处理事件的速度时(不妨称呼这种现象为“流量过大”),未被及时处理的事件会被缓存在内存中等待处理。如果这种状况得不到改善的话,随着时间的推移,堆积在内存中的待处理事件会越来越多,程序的内存占用会越来越高,最终结果就是导致内存溢出(OOM)和程序崩溃。

背压(backpressure)是解决“流量过大”问题的手段之一(背压的具体信息后面会介绍)。

在RxJava1.x中,支持背压和不支持背压的被观察者都是Observable,对于使用者而言,很容易混淆和误用。而RxJava2.0与RxJava1.x相比最大区别就是,引入了一个新的基类Flowable用以表示支持背压的被观察者,并且Observable的代码也被重写,用以表示不支持背压的被观察者,简单的说就是:Flowable——支持背压,Observable——不支持背压。

2.类与方法概览

根据是否支持背压,RxJava2.0中的类可以被大致划分为两个体系:Flowable-Subscriber体系 和 Observable-Observer体系,如下所示。大致了解一下即可,下一小节会有详细的使用示例和解释。

Observer用于订阅Observable,而Subscriber用于订阅Flowable(及其他Publisher的实现类)。

Observable-Observer体系(不支持背压)

Observable<T> implements ObservableSource<T>{...}

public interface ObservableSource<T> {
    void subscribe(Observer<? super T> observer);
}

//Observer用于订阅Observable
public interface Observer<T> {

    //当订阅(subscribe)发生时被调用,在此方法中可以获得Disposable对象(用以取消订阅关系)
    //Provides the Observer with the means of cancelling (disposing) the connection (channel) with the Observable in both synchronous (from within onNext(Object)) and asynchronous manner.
    //d:the Disposable instance whose Disposable.dispose() can be called anytime to cancel the connection
    void onSubscribe(Disposable d);

    void onNext(T t);

    void onError(Throwable e);

    void onComplete();
}

//用以取消订阅关系(dispose方法)
public interface Disposable {

    //取消当前Observer和Observable之间的订阅关系
    void dispose();

    boolean isDisposed();
}

Flowable-Subscriber体系(支持背压)

除了是否支持背压之外,Flowable与Observable还有一个区别,就是:Flowable发出事件之后,事件并不直接发送给观察者Subscriber(即便此时Subscriber是空闲的),而是将事件缓存在内存中,只有当调用了subscription.request(n)之后,事件才会被发送给观察者Subscriber。

Flowable<T> implements Publisher<T>{...}

public interface Publisher<T> {
    void subscribe(Subscriber<? super T> s);
}

//Subscriber用于订阅Flowable(及其他Publisher的实现类)
public interface Subscriber<T> {

    //当订阅(subscribe)发生时被调用,在此方法中可以获得Subscription对象
    //Invoked after calling Publisher.subscribe(Subscriber).
    //No data will start flowing until Subscription.request(long) is invoked.
    //It is the responsibility of this Subscriber instance to call Subscription.request(long) whenever more data is wanted.
    //The Publisher will send notifications only in response to Subscription.request(long).
    void onSubscribe(Subscription s);

    void onNext(T t);

    void onError(Throwable t);

    void onComplete();
}

//有两个功能:1.请求Flowable发出事件(request方法) 2.取消订阅关系(cancel方法)
public interface Subscription {

    //请求Flowable发出事件
    public void request(long n);

    //取消当前Subscriber与Flowable的订阅关系
    //Request the Publisher to stop sending data and clean up resources.
    //Data may still be sent to meet previously signalled demand after calling cancel.
    public void cancel();
}

3 使用示例

3.1 基本使用

Observable-Observer体系:

可以发现,使用方式与RxJava1.x基本一样,只是细节上有一点区别。

Observable
        .create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(@NonNull ObservableEmitter<Integer> e) throws Exception {
                e.onNext(1);
                e.onNext(2);
                e.onComplete();
            }
        })
        .subscribe(new Observer<Integer>() {
            //当订阅(subscribe)发生时被调用,Disposable对象用来取消订阅关系(dispose方法)
            @Override
            public void onSubscribe(@NonNull Disposable d) {
            }

            @Override
            public void onNext(@NonNull Integer integer) {
                Log.e("log", "处理:" + integer);
            }

            @Override
            public void onError(@NonNull Throwable e) {
            }

            @Override
            public void onComplete() {
            }
        });

Flowable-Subscriber体系:

因为Flowable支持背压,因此在通过create创建Flowable对象的时候,需要传入一个背压策略参数(BackpressureStrategy,后面详细说)。

此外,Subscriber需要调用Subscription的request方法,才能获取到Flowable发出的事件。

Flowable
        .create(new FlowableOnSubscribe<Integer>() {
            @Override
            public void subscribe(@NonNull FlowableEmitter<Integer> e) throws Exception {
                e.onNext(1);
                e.onNext(2);
                e.onComplete();
            }
        }, BackpressureStrategy.BUFFER)
        .subscribe(new Subscriber<Integer>() {
            Subscription subscription;

            //当订阅(subscribe)发生时被调用
            //Subscription对象可以用来请求Flowable发出事件(request方法),以及取消订阅关系(cancel方法)
            @Override
            public void onSubscribe(Subscription s) {
                subscription = s;
                subscription.request(1);//先获取一个事件,这样onNext才能接收到第一个事件
            }

            @Override
            public void onNext(Integer integer) {
                Log.e("log", "处理:" + integer);
                subscription.request(1);//获取下一个事件
            }

            @Override
            public void onError(Throwable t) {
            }

            @Override
            public void onComplete() {
            }
        });

3.2 简化代码

同RxJava1.x类似,RxJava2.0也提供了一系列fromXXX(…)和just(…)方法用来简化被观察者的创建。以Flowable为例,让我们简单看看这两类方法都有哪些重载:

fromArray(T... items)
fromCallable(Callable<? extends T> supplier)
fromFuture(...)
fromIterable(Iterable<? extends T> source)
fromPublisher(Publisher<? extends T> source)

just(T item)
just(T item1, T item2)
...
just(T item1, T item2, T item3, T item4, T item5, T item6, T item7, T item8, T item9, T item10)

Flowable的subscribe方法也有众多重载,用来简化Subscriber的创建:

subscribe(Consumer<? super T> onNext)
subscribe(Consumer<? super T> onNext, Consumer<? super Throwable> onError)
subscribe(Consumer<? super T> onNext, Consumer<? super Throwable> onError, Action onComplete)
subscribe(Consumer<? super T> onNext, Consumer<? super Throwable> onError, Action onComplete, Consumer<? super Subscription> onSubscribe)

其中:
public interface Consumer<T> {
    void accept(T t) throws Exception;
}
public interface Action {
    void run() throws Exception;
}

Consumer其实就是RxJava1.x中的Action1,即对单参数无返回值的函数的封装,只是换了个名字而已。而Action其实就是RxJava1.x中的Action0,即对无参数无返回值的函数的封装。

有了上面这些方法,之前关于Flowable-Subscriber的示例代码就可以简化成这样:

Flowable.just(1, 2)
        .subscribe(new Consumer<Integer>() {
            @Override
            public void accept(Integer integer) throws Exception {
                Log.e("log", "处理:" + integer);
            }
        });

输出:
E/log: 处理:1
E/log: 处理:2

4 背压详解

4.1 Observable-Observer体系

事件发送与处理在同一线程

Observable
        .create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(@NonNull ObservableEmitter<Integer> e) throws Exception {

                for (int i = 1; i < 10; i++) {
                    Log.e("log", "发送:" + i);
                    e.onNext(i);
                    SystemClock.sleep(100);
                }
                Log.e("log", "发送:onComplete");
                e.onComplete();
            }
        })
        .subscribe(new Observer<Integer>() {
            @Override
            public void onSubscribe(@NonNull Disposable d) {

            }

            @Override
            public void onNext(@NonNull Integer integer) {
                Log.e("log", "处理:" + integer);
                SystemClock.sleep(1000);
            }

            @Override
            public void onError(@NonNull Throwable e) {
                Log.e("log", "处理:onError——" + e.toString());
            }

            @Override
            public void onComplete() {
                Log.e("log", "处理:onComplete");
            }
        });

输出:
E/log:发送:1
E/log:处理:1
E/log:发送:2
E/log:处理:2
E/log:发送:3
E/log:处理:3
E/log:发送:4
E/log:处理:4
E/log:发送:5
E/log:处理:5
E/log:发送:6
E/log:处理:6
E/log:发送:7
E/log:处理:7
E/log:发送:8
E/log:处理:8
E/log:发送:9
E/log:处理:9
E/log:发送:onComplete
E/log:处理:onComplete

当事件发送与处理在同一线程时,遵循发送一个,处理一个,再发送一个,再处理一个……这样的规律。这是由单线程和函数调用关系决定的(参考源码)。

事件发送与处理在不同线程

Observable
        .create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(@NonNull ObservableEmitter<Integer> e) throws Exception {

                for (int i = 1; i < 10; i++) {
                    Log.e("log", "发送:" + i);
                    e.onNext(i);
                    SystemClock.sleep(100);
                }
                Log.e("log", "发送:onComplete");
                e.onComplete();
            }
        })
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(new Observer<Integer>() {
            @Override
            public void onSubscribe(@NonNull Disposable d) {

            }

            @Override
            public void onNext(@NonNull Integer integer) {
                Log.e("log", "处理:" + integer);
                SystemClock.sleep(1000);
            }

            @Override
            public void onError(@NonNull Throwable e) {
                Log.e("log", "处理:onError——" + e.toString());
            }

            @Override
            public void onComplete() {
                Log.e("log", "处理:onComplete");
            }
        });

输出:
E/log:发送:1
E/log:处理:1
E/log:发送:2
E/log:发送:3
E/log:发送:4
E/log:发送:5
E/log:发送:6
E/log:发送:7
E/log:发送:8
E/log:发送:9
E/log:发送:onComplete
E/log:处理:2
E/log:处理:3
E/log:处理:4
E/log:处理:5
E/log:处理:6
E/log:处理:7
E/log:处理:8
E/log:处理:9
E/log:处理:onComplete

可见,由于事件发出和处理不在同一线程,因此二者互不影响。事件的发出速度是处理速度的十倍,得不到及时处理的事件就会被缓存在内存中。本例中只有10个事件,因此并不足以造成什么严重后果,但如果事件非常多呢?越来越多的事件因得不到及时处理而堆积在内存中,最终势必会造成内存溢出(OOM)。

4.2 Flowable-Subscriber体系

事件发送与处理在不同线程

Flowable
        .create(new FlowableOnSubscribe<Integer>() {
            @Override
            public void subscribe(@NonNull FlowableEmitter<Integer> e) throws Exception {

                for (int i = 1; i < 10; i++) {
                    Log.e("log", "发送:" + i);
                    e.onNext(i);
                    SystemClock.sleep(100);
                }
                Log.e("log", "发送:onComplete");
                e.onComplete();
            }
        }, BackpressureStrategy.BUFFER)
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(new Subscriber<Integer>() {
            Subscription subscription;

            @Override
            public void onSubscribe(Subscription s) {
                subscription = s;
                subscription.request(1);
            }

            @Override
            public void onNext(Integer integer) {
                Log.e("log", "处理:" + integer);
                SystemClock.sleep(1000);
                subscription.request(1);
            }

            @Override
            public void onError(Throwable t) {
                Log.e("log", "处理:onError——" + t.toString());
            }

            @Override
            public void onComplete() {
                Log.e("log", "处理:onComplete");
            }
        });

输出:
E/log: 发送:1
E/log: 处理:1
E/log: 发送:2
E/log: 发送:3
E/log: 发送:4
E/log: 发送:5
E/log: 发送:6
E/log: 发送:7
E/log: 发送:8
E/log: 发送:9
E/log: 发送:onComplete
E/log: 处理:2
E/log: 处理:3
E/log: 处理:4
E/log: 处理:5
E/log: 处理:6
E/log: 处理:7
E/log: 处理:8
E/log: 处理:9
E/log: 处理:onComplete

背压策略

当事件发出的速度比事件被取走(调用subscription.request(n)方法)的速度快时,没有被及时取走的事件会被缓存起来,但这个缓存空间是有限的——最多能容纳128个事件。那么,当缓存空间已满,又有新的事件发出时该怎么办呢?这就是背压策略所要解决的问题。

(回顾一下Observable-Observer体系:Observable会直接将事件发送给Observer(即无需调用request之类的方法),但如果此时Observer“没空”的话,事件就会被缓存起来,此缓存空间是无限的,直到发生OOM)

/**
 * Represents the options for applying backpressure to a source sequence.
 */
public enum BackpressureStrategy {

    /**
     * OnNext events are written without any buffering or dropping.
     * Downstream has to deal with any overflow.
     * Useful when one applies one of the custom-parameter onBackpressureXXX operators.
     */
    MISSING,

    /**
     * 缓存已满时再发出新事件就抛出MissingBackpressureException异常。
     * Signals a MissingBackpressureException in case the downstream can't keep up.
     */
    ERROR,

    /**
     * 缓存所有事件(即取消对缓存空间大小的限制,可能导致OOM)。
     * Buffers all onNext values until the downstream consumes it.
     */
    BUFFER,

    /**
     * 缓存已满时再发出新事件就丢弃新事件。
     * Drops the most recent onNext value if the downstream can't keep up.
     */
    DROP,

    /**
     * 缓存已满时再发出新事件就用新事件覆盖缓存中的最后一个事件。
     * Keeps only the latest onNext value, overwriting any previous value if the
     * downstream can't keep up.
     */
    LATEST
}

测试代码如下:

(日志输出太多了,所以结果就不贴出来了。自己更换不同的背压策略跑跑试试吧,实践出真知!)

Flowable
        .create(new FlowableOnSubscribe<Integer>() {
            @Override
            public void subscribe(@NonNull FlowableEmitter<Integer> e) throws Exception {

                for (int i = 1; i < 200; i++) {
                    Log.e("log", "发送:" + i);
                    e.onNext(i);
                    SystemClock.sleep(50);
                }
                Log.e("log", "发送:onComplete");
                e.onComplete();
            }
        }, BackpressureStrategy.LATEST)
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(new Subscriber<Integer>() {
            Subscription subscription;

            @Override
            public void onSubscribe(Subscription s) {
                subscription = s;
                subscription.request(1);
            }

            @Override
            public void onNext(Integer integer) {
                Log.e("log", "处理:" + integer);
                SystemClock.sleep(500);
                subscription.request(1);
            }

            @Override
            public void onError(Throwable t) {
                Log.e("log", "处理:onError——" + t.toString());
            }

            @Override
            public void onComplete() {
                Log.e("log", "处理:onComplete");
            }
        });

在Android开发中,很少会遇到事件发出速度高于事件处理速度并持续很长时间的情况,因此通常使用Observable和Observer就足够了。

发布了46 篇原创文章 · 获赞 38 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/al4fun/article/details/77604448