UDN-企业互联网技术人气社区

板块导航

浏览  : 1159
回复  : 0

[讨论交流] RxJava 具有副作用的方法

[复制链接]
呵呵燕的头像 楼主
发表于 2016-9-10 19:38:02 | 显示全部楼层 |阅读模式
  RxJava 有许多方法可以把流中的数据项转化成需要的数据,它们是 RxJava 的核心,也是最吸引人的部分。与之对应的是,其它方法不更改流中的数据项,我称它们为副作用方法。

  副作用方法

  虽然副作用方法不影响流,但它们会在一些特定的事件中被调用,从而响应这些事件。比如:当一个被订阅的流产生错误的时候,可以 doOnError() 会被调用,这时把一些调试代码写在 doOnError() 里,就能知道到底发生了什么错误。

  1.   someObservable

  2.   .doOnError(new Action1() {

  3.   @Override

  4.   public void call(Throwable t) {

  5.   // use this callback to clean up resources,

  6.   // log the event or or report the

  7.   // problem to the user

  8.   }

  9.   })

  10.   //…
复制代码


  在 call() 方法的代码会在订阅者的 onError() 方法之前调用。除了异常事件,RxJava 提供了很多回调方法用来响应各种事件:

  副作用方法和事件的关系

effect_methods.png


  范型 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.   Observable someObservable = Observable

  2.   .from(Arrays.asList(new Integer[]{2, 3, 5, 7, 11}))

  3.   .doOnNext(System.out::println)

  4.   .filter(prime -> prime % 2 == 0)

  5.   .doOnNext(System.out::println)

  6.   .count()

  7.   .doOnNext(System.out::println)

  8.   .map(number -> String.format(“Contains %d elements”, number));

  9.   Subscription subscription = o.subscribe(

  10.   System.out::println,

  11.   System.out::println,

  12.   () -> System.out.println(“Completed!”));
复制代码


  运行结果如下:

 
  1.  2

  2.   3

  3.   3

  4.   5

  5.   5

  6.   7

  7.   7

  8.   11

  9.   11

  10.   4

  11.   Contains 4 elements

  12.   Completed!
复制代码


  这种方法可以查看数据的值,当流的数据不符合预期的时候特别有用。

  doOnError() 和 doOnCompleted() 也能用来调试。

  如果你在开发 Android App 时使用了 RxJava,可以使用 Frodo(使用了注解)调试 Observables 和 Subscribers。具体用法可以参考 Fernando Ceja 的博客

  尽管 doOnNext() 和 doOnError() 的使用会增加你的日志,并且会拖慢你的系统。:–) 当需要改变系统状态时,还是适用的,接着来看。

  flatMap() 中调用 doOnError()

  因为支持 RxJava,Retrofit 特别适合在网络请求时使用,而在数据请求链中会经常使用到 flatMap() 方法,是因为网络调用容易出错,特别是在移动设备上,但是出错时又不想停止数据调用链,这时唯一可用的就只有 onError()方法了。不过别忘了还有 flatMap(),在它里面调用doOnError修改 UI 状态,还能进行出错后的数据处理,代码如下:

  1.   flatMap(id -> service.getPost()

  2.   .doOnError(t -> {

  3.   // report problem to UI

  4.   })

  5.   .onErrorResumeNext(Observable.empty())

  6.   )
复制代码


  这种用法特别适合用来查看远程数据对 UI 状态的影响。

  使用 doOnNext() 保存/缓存网络数据

  如果在链式调用过程中有网络调用,可以使用 doOnNext() 把获得的数据存入数据库或者缓存起来。只需要几行简单的代码:

  1.   // getOrderById is getting a fresh order

  2.   // from the net and returns an observable of orders

  3.   // Observable getOrderById(long id) {…}

  4.   Observable.from(aListWithIds)

  5.   .flatMap(id -> getOrderById(id)

  6.   .doOnNext(order -> cacheOrder(order))

  7.   // carry on with more processing
复制代码


  Daniel Lew 的 accessing multiple sources 里,详细介绍了这种用法。

  小结

  正如上面所说,副作用方法有多种用途,虽然不能影响流中数据,但却能改变周边的环境状态。这让在某个时刻记录数据流变得很简单,更不用说把网络调用获得的数据存入数据库了。

原文作者:Neater 来源:开发者头条

相关帖子

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关于我们
联系我们
  • 电话:010-86393388
  • 邮件:udn@yonyou.com
  • 地址:北京市海淀区北清路68号
移动客户端下载
关注我们
  • 微信公众号:yonyouudn
  • 扫描右侧二维码关注我们
  • 专注企业互联网的技术社区
版权所有:用友网络科技股份有限公司82041 京ICP备05007539号-11 京公网网备安1101080209224 Powered by Discuz!
快速回复 返回列表 返回顶部