RxJava 的 compose() 操作函数实战

作者: rain 分类: 移动 发布时间: 2016-05-12 23:09 6 条评论

如果你对 RxJava 还不了解,请参考Intro To RxJava 系列教程,如果你看了其中的自定义操作函数后,认为 compose 操作函数只在自定义操作函数中才需要使用,则 Dan lew 通过这篇文章告诉你,并非如此。 很多情况我们都可以使用 compose 函数。

RxJava 一大特性就是串联调用各种操作函数,这样代码看起来比较整洁,也能清晰的表达代码所要实现的功能,例如:

特别是在实现请求网络的时候,每次都需要使用 subscribeOn() 和 observeOn() 函数来指定在 IO 线程请求网络,在 UI 线程处理返回的数据。如果这两个函数的调用能够封装到一个函数中来复用,这样写代码是不是更加简单一些。

在没有发现 compose 之前是这么干的

在刚刚开始接触 RxJava 的时候,我是通过下面的方式来实现复用的:

然后用上面的函数把 Observable 包裹起来(Observable 为上面函数的参数):

虽然上面的代码实现了需要的功能,但是看起来太难看了,也太费解了 — applySchedulers() 到底干了啥? 如果在同一个 Observable 多次使用了类似的代码,则看起来是不是更加头疼。

Transformer 闪亮登场

聪明的 RxJava 开发者团队已经意识到这个问题,并且提供了一个解决方式: TransformerObservable.compose().

Transformer 其实就是 Func1<Observable, Observable> 这个接口,只不过起了一个更好听的名字。参数是一个 Observable,返回另外一个类型的 Observable。 Observable 的很多数据处理的操作函数也都是这样的。

使用 Transformer 来实现一开始需要的功能:

使用 lambdas 表达式更加简单一些:

然后和 compose 一起使用:

看起来是不是简洁多了,并且代码还是可以串联的调用。

上面的代码在低于 JDK 8 的 SDK 中无法正确编译。由于 之前的 JDK 无法通过返回值来推导泛型类型的参数,你需要明确的告诉编译器返回的参数类型:

复用 Transformer

上面的代码在每次只需该操作的时候都会创建一个新的 Transformer 实例。 其实通过创建一个 Transformer 实例来使用可以避免该问题。

如果你需要把 Observable 从一个确定的类型转换为另外一个确定的类型,则可以这样创建一个示例:

但是我们上面线程调度的 Transformer 类型是不确定的,但是无法定义一个泛型的 Transformer 实例:

虽然可以使用 Transformer<Object, Object>,但是返回的 Observable 的类型就丢失了,导致返回的 Observable 不太好用。

在 Java sdk 中的 Collections 中有个解决该问题的方式,一些创建类型安全的不可变空集合的函数。内部使用非泛型的示例,返回的时候通过泛型来转换。

使用通用的技巧,我们的 Transformer 实例如下:

这样我们可以宠用这同一个实例了,不用每次都创建一个新的 Transformer 实例。

注意:上面的类型转换是不安全的,这就要求你的 Transformer 实现确实是无关类型的。比如这里的线程调度的两个函数,他们是不会修改 Observable 的类型的,所以可以这样使用。

flatMap() 是干啥的呢?

flatMap() 的返回值也是 Observable, 是不是就意味着 flatMap 也可以重用部分操作函数?

他们的区别在于,compose() 是更高层的抽象: 他的操作是作用在整个事件流上的,而不是里面发射的单个数据。具体来讲就是:

  1. 只能通过 compose() 来从数据流中获取源 Observable 。所以对于影响整个事件流的操作函数(例如 subscribeOn() 和 observeOn())需要使用 compose()。
    如果你把 subscribeOn()/observeOn() 在 flatMap 内使用,则只会对在 flatMap 里面创建的 Observable 有用而不是整个数据流。

  2. 一旦创建了事件流,compose() 就立刻开始执行了。而flatMap() 只有当每次 onNext() 调用的时候才开始执行。也就是说,flatMap() 转换的是每个单独的数据而 compose() 是作用在整个数据流上的。

  3. 由于每次调用 Observable 的 onNext() 函数 flatMap() 都会创建一个新的 Observable。所以 flatMap() 的效率并不是很好。

结论:

如果你只是想把几个常用的操作函数封装为一个函数来复用代码,则请使用 compose()。 flatMap() 有很多种用法的,但是并不适合这种情况。

本文出自 云在千峰,转载时请注明出处及相应链接。

本文永久链接: http://blog.chengyunfeng.com/?p=987

Ɣ回顶部