RxJava 有许多方法可以把流中的数据项转化成需要的数据,它们是 RxJava 的核心,也是最吸引人的部分。与之对应的是,其它方法不更改流中的数据项,我称它们为副作用方法。
副作用方法
虽然副作用方法不影响流,但它们会在一些特定的事件中被调用,从而响应这些事件。比如:当一个被订阅的流产生错误的时候,可以 doOnError() 会被调用,这时把一些调试代码写在 doOnError() 里,就能知道到底发生了什么错误。
1 2 3 4 5 6 7 8 9 10 |
|
在 call() 方法的代码会在订阅者的 onError() 方法之前调用。除了异常事件,RxJava 提供了很多回调方法用来响应各种事件:
副作用方法和事件的关系
范型 T 在 doOnNext() 调用时表示数据的类型,在 doOnError() 调用时则是异常的类型。回调类型则有 Action0 和 Action1,说明这些回调方法没有返回值,没有或者只有一个参数。正因为没有返回值,它们不会在需要改变数据项时调用,它们适合在产生副作用的地方,比如保存数据到本地、清空状态值等等。
需要注意的是,这些副作用方法(doOnNext(), doOnCompleted() and so on)会返回 Observable,可以保持方法的链式调用。
有什么用
利用它们不更改流中的数据的特性,可以满足下面三种需求:
- doOnNext(): 调试
- doOnError() in flatMap(): 错误处理
- doOnNext(): 保存/缓存数据
来看看详细用法。
doOnNext(): 调试
在使用 RxJava 的过程中,Observable 有时并不会像预期运行,尤其是刚上手的那段时间,这时特别想知道发生了什么。还有当你通过某些方便的转换方法,是不是想看看每个数据项转换后的结果。
我开始接触 RxJava 的时候只有一些 Java 流的经验,想必你也一样吧。使用内置的方法可以把流中的数据转换成另一种类型,如果转换过程出现问题了呢?
Java 8 Streaming 的 peek() 方法可以调试这个问题,当我开始使用 RxJava 时自然想用与之类似的方法,幸运的是有,事实上,它不仅如此!
可以在任何流发送的过程中调用 doOnNext() 查看流中的每项数据,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
运行结果如下:
1 2 3 4 5 6 7 8 9 10 11 12 |
|
这种方法可以查看数据的值,当流的数据不符合预期的时候特别有用。
doOnError() 和 doOnCompleted() 也能用来调试。
如果你在开发 Android App 时使用了 RxJava,可以使用 Frodo(使用了注解)调试 Observables 和 Subscribers。具体用法可以参考 Fernando Ceja 的博客
尽管 doOnNext() 和 doOnError() 的使用会增加你的日志,并且会拖慢你的系统。:–) 当需要改变系统状态时,还是适用的,接着来看。
flatMap() 中调用 doOnError()
因为支持 RxJava,Retrofit 特别适合在网络请求时使用,而在数据请求链中会经常使用到 flatMap() 方法,是因为网络调用容易出错,特别是在移动设备上,但是出错时又不想停止数据调用链,这时唯一可用的就只有 onError()方法了。不过别忘了还有 flatMap(),在它里面调用 doOnError修改 UI 状态,还能进行出错后的数据处理,代码如下:
1 2 3 4 5 6 |
|
这种用法特别适合用来查看远程数据对 UI 状态的影响。
使用 doOnNext() 保存/缓存网络数据
如果在链式调用过程中有网络调用,可以使用 doOnNext() 把获得的数据存入数据库或者缓存起来。只需要几行简单的代码:
1 2 3 4 5 6 7 8 |
|
Daniel Lew 的 accessing multiple sources 里,详细介绍了这种用法。
小结
正如上面所说,副作用方法有多种用途,虽然不能影响流中数据,但却能改变周边的环境状态。这让在某个时刻记录数据流变得很简单,更不用说把网络调用获得的数据存入数据库了。
接下来的博客,会进一步介绍 RxJava hook,敬请期待!
译自 http://www.grokkingandroid.com/rxjavas-side-effect-methods/