RxJava 2.x.x Observable 与 Observer 入门分析

来源:互联网 发布:涌泉知恩 编辑:程序博客网 时间:2024/05/22 05:11

概要

RxJava 是响应式扩展(Reactive Extension) 在 Java 和 Android 上的实现。 RxJava 以观察者模式为基础,扩展大量的操作符,解决了异步或基于事件驱动的编程问题。

Observable

Observable< T > 代表数据或者事件的流,在 Android 中,当你多次点击一个 Button 的时候就会产生一个点击事件流。

Observable< T > 通过调用 ObservableEmitter 的方法可以产生三种类型的事件:

  • ObservableEmitter.onNext(),用来发送类型为 T 的数据
  • ObservableEmitter.onComplete(),完成事件,是一个终止事件
  • ObservableEmitter.onError(),错误事件,也是一个终止事件

onNext() 是发送事件,Observable 可以发送 0 个,1 个,甚至无限个事件。 而 onError() 和 onComplete() 是终止事件,有且只能有一个出现,当终止事件发生后,也就不会再有事件发送了。

订阅 Observable 事件

虽然 Observable 有发送事件的能力,但是仅仅只拥有 Observable 对象是不会发送任何事件的,现在来创建一个 Observable 对象

        Observable<Integer> observable = Observable.create(new ObservableOnSubscribe<Integer>() {            @Override            public void subscribe(@NonNull ObservableEmitter<Integer> e) throws Exception {                Log.d(TAG, "onNext(1)");                e.onNext(1);                Log.d(TAG, "onNext(2)");                e.onNext(2);                Log.d(TAG, "onComplete()");                e.onComplete();            }        });

这个匿名内部类对象太长了,用 Lambda 表达式简化下

        // create observable instance        Observable<Integer> observable = Observable.create(e -> {            Log.d(TAG, "onNext(1)");            e.onNext(1);            Log.d(TAG, "onNext(2)");            e.onNext(2);            Log.d(TAG, "onComplete()");            e.onComplete();        });

运行上面代码,不会看到任何 Log 信息。 因为只有当 Observable 对象被订阅了,Observable 对象才会产生事件

        // subscribe observable, only receive events, but do nothing        observable.subscribe();

那么现在运行代码,可以看到 Log 信息了。

然而,这个订阅的方式却相当的奇怪,居然是用 Observable 对象来调用订阅方法 subscribe(),我想应该是为了方便函数式调用

Observable.create(e -> e.onNext(1)).subscribe();

这样看起来是不是就很简洁呢?

然而,我们发现一个问题 ,observable.subscribe() 订阅后,虽然产生了事件,但是我们并没有处理事件。那么怎么处理事件呢,我想你一定会猜到向 subscribe() 方法里传入参数来处理事件,俗称 Callback。

通过查看,可以发现 subscribe() 方法有5个重载的方法,如截图所示。
这里写图片描述

这些重载方法都是有规律可循的,先来看只有一个参数的方法。

        observable.subscribe(new Consumer<Integer>() {            @Override            public void accept(Integer integer) throws Exception {            }        });

从截图中看这个参数的命名,你应该猜到第一个 Callback 是处理 onNext() 事件的,现在我们用 Lambda 表达式来简化下,后面的我讲都用 Lambda 表达式简化代码

        // subscribe observable , only receive onNext() event        observable.subscribe(integer -> Log.d(TAG, "integer = " + integer));

再运行代码的时候,就可以看到处理 onNext() 事件的的 Log 了。

从截图中可以看出,第二个参数名为 onError,也就是处理 onError() 事件,那么为什么会有 onError() 事件?

因为 Observable 不会抛出异常,然而如果有异常发生,Observable 会发送一个通知事件,这个事件就是 onError(),因此你不必用 try-catch 代码块包含 subscribe() 方法来捕获异常,而你需要做的就是提供一个回调来接收 onError() 事件,这就是 subscribe() 方法的第二个参数的用法。

还有一个总是,我们是否需要关心 onComplete() 事件?

对于一个无限流来说,接收 onComplete() 事件是无意义的,而对于一个有限流来说,是否需要接收 onComplete() 事件还要取决于 Subscriber。例如,如果我用 Observable< Progress > 来监测文件的下载进度,其实中间的过程我们并不在意,而我们真正在意的是这个文件什么时候下载成功,也就是什么时候接收 onComplete() 事件。

这次索性直接看三个参数的方法

        // subscribe observable , receive onNext, onError, onComplete events        observable.subscribe(                integer -> Log.d(TAG, "integer = " + integer),                throwable -> Log.d(TAG, "error!!!"),                () -> Log.d(TAG, "complete!!"));

运行代码后,只能看到处理的 onNext, onComplete 事件,因为 Observable 对象没有发送 onError 事件,然而一定要记住,onComplete 和 onError 事件是能出现其中一个。

如果对 subscribe() 参数不熟悉,可以先创建匿名内部类对象,再转化为 Lambda 表达式

最后看看四个参数的 subscribe() 方法

        // subscribe observable , receive all events        observable.subscribe(                integer -> Log.d(TAG, "integer = " + integer),                throwable -> Log.d(TAG, "error!!!"),                () -> Log.d(TAG, "complete!!"),                disposable -> Log.d(TAG, "disposable!!"));

disposable 翻译为一次性的东西,尤其指容器,这里可以理解为一个管道,连通 Observable 的管道。从上面截图中可以看出,最后一个参数叫 onSubscribe,代表订阅成功后的 Callback,与 onClickListener 中的 onClick 回调方法有异曲同工之妙。

运行下代码看看 Log 信息

david: disposable!!david: onNext(1)david: integer = 1david: onNext(2)david: integer = 2david: onComplete()david: complete!!

从Log中看,首先要成功建立订阅关系,然后才能发送事件。

现在,我们知道如何订阅 Observable 对象,如何处理事件,但是处理事件的时候,几个参数写的有点麻烦,怎么办呢,把这几个回调方法封装到一起,就成为了我们熟悉的 Observer< T > 接口了,现在来创建一个 Observer 对象

        Observer<Integer> observer = new Observer<Integer>() {            @Override            public void onSubscribe(@NonNull Disposable d) {            }            @Override            public void onNext(@NonNull Integer integer) {            }            @Override            public void onError(@NonNull Throwable e) {            }            @Override            public void onComplete() {            }        };

perfect! 创建完 Observer 对象,剩下就是订阅了

observable.subscribe(observer);

这就是 subscribe() 方法的最后一个重载方法了。

最后用一个函数式编程风格代码来做个总结

        Observable.create((ObservableOnSubscribe<Integer>) e -> {            e.onNext(1);            e.onNext(2);            e.onComplete();        }).subscribe(new Observer<Integer>() {            @Override            public void onSubscribe(@NonNull Disposable d) {            }            @Override            public void onNext(@NonNull Integer integer) {            }            @Override            public void onError(@NonNull Throwable e) {            }            @Override            public void onComplete() {            }        });

控制订阅关系

我们知道 Observable 对象可以发送任意数量的 onNext 事件

        private int i;        Observable.create((ObservableOnSubscribe<Integer>) e -> {            while (true) {                e.onNext(i++);            }        })

但是 Observer 对象订阅 Observerable 对象后,并不想处理所有的 onNext 事件,那就只能取消订阅关系,我们可以用 Disposal 对象调用 dispose() 方法取消订阅。

Disposable

Disposal 对象取消订阅的方式分为两种,一种是外部取消,一种是内部取消。

内部取消订阅,我们用给 Observable.subscribe() 传入 Observer 对象举例

        private int i;        Observable.create((ObservableOnSubscribe<Integer>) e -> {            while (true) {                e.onNext(i++);            }        }).subscribe(new Observer<Integer>() {            private Disposable mDisposable;            @Override            public void onSubscribe(@NonNull Disposable d) {                mDisposable = d;            }            @Override            public void onNext(@NonNull Integer integer) {                Log.d(TAG, "integer = " + integer);                if (integer == 100 && !mDisposable.isDisposed()) {                    mDisposable.dispose();                }            }            @Override            public void onError(@NonNull Throwable e) {            }            @Override            public void onComplete() {            }        });

从代码中可以看出,在 onSubscribe() 方法中,我们可以获取到 Dispoasble 对象 d(我称之为管道),然后在 onNext() 方法中,如果这个 integer 值等于 100 了 , 并且管道 d 还没有被切断,那么就切断管道。 这样一来,就不会再接收事件了,也就是说 100 之后的数据就不再有了。

那么 Observable.subscribe() 的四个参数的重载方法切断管道的原理也就是类似了。

        private int i;        private Disposable mDisposable;        Observable.create((ObservableOnSubscribe<Integer>) e -> {            while (true) {                e.onNext(i++);            }        }).subscribe(                integer -> {                    if (integer == 999 && !mDisposable.isDisposed()) {                        mDisposable.dispose();                    }                    Log.d(TAG, "integer = " + integer);                },                throwable -> Log.d(TAG, "error"),                () -> Log.d(TAG, "complete"),                disposable -> mDisposable = disposable        );

那怎么用 Disposal 对象外部取消订阅呢? 其实如果 Observerable.subscribe() 方法传入的不是 Observer 对象,那么可以生成 Disposal 对象

        Disposable d = Observable.create((ObservableOnSubscribe<Integer>) e -> {            while (true) {                e.onNext(1);                e.onNext(2);                e.onNext(3);            }        }).subscribe(                integer -> Log.d(TAG, "integer = " + integer)        );

获取到 Disposal 对象 d 后,就可以来取消订阅了

d.dispose();

如果 Observerable.subscribe() 方法传入的是 Observer 对象,那么是没有返回值的,因为 Observer 对象本身就可以获取到 Disposable 对象,如果再返回,岂不是多此一举。

然而,当我们运行程序后发现,却发现Observerable 对象发送的事件并没有在停止,why? 因为这个 Observerable 发送事件是在主线程中的,所以 d.dispose() 并没有执行。如果要想从外面取消订阅,这个 Observerable 不能运行在主线程中,当然这是后话了。

总结

本篇文章主要是对 RxJava 有个大致的理解,并对 Observable 和 Observer 稍作分析,当做 RxJava 2.x.x 的一个入门吧。

原创粉丝点击