深入浅出RxJava(二:操作符)

发布时间:2023-05-09 09:52:24

在 第一篇blog 在中间,我介绍了RxJava的一些基础知识,也介绍了map()操作符。当然,如果你不想用RxJava,我一点也不惊讶。毕竟我接触过这么多。看完这个blog,相信你一定想马上在你的项目中使用RxJava。这个blog将介绍RxJava中的许多操作符。RxJava的强度来自于它定义的操作符。 先看一个例子:

准备工作

假设我有这样的方法:

该方法根据输入字符串返回网站url列表(啊哈,搜索引擎)

[java] view plain copy

1. Observable<List<String>> query(String text);

现在我想建立一个强大的系统,它可以查询字符串并显示结果。根据上一个blog的内容,我们可以编写以下代码:

[java] view plain copy

1. query("Hello, world!")  2.     .subscribe(urls -> {  3. for (String url : urls) {  4.             System.out.println(url);  5.         }  6.     });

当然,这种代码是不能容忍的,因为上述代码使我们失去了改变数据流的能力。一旦我们想改变每个URL,我们只能在Subscriber中完成。我们没有使用这么酷的map()操作符!!!

当然,我可以使用map操作符。map的输入是urls列表,处理时仍需for each遍历,同样的蛋疼。

幸运的是,还有Observable.from()方法,它接收集合作为输入,然后每次向subscriber输出一个元素:

[java] view plain copy

1. Observable.from(url1), “url2”, “url3”  2.     .subscribe(url -> System.out.println(url));

让我们在刚才的场景中使用这种方法:

[java] view plain copy

1. query("Hello, world!")  2.     .subscribe(urls -> {  3.         Observable.from(urls)  4.             .subscribe(url -> System.out.println(url));  5.     });

尽管去掉了for each循环,但代码看起来仍然很混乱。多嵌套subscription不仅看起来丑陋,而且难以修改,更严重的是,它会破坏RxJava的一些特性,我们还没有提到。

改进

救星来了,他是flatMap()。

Observable.flatMap()接收Observable的输出作为输入,同时输出另一个Observable。直接查看代码:

[java] view plain copy

1. query("Hello, world!")  2. new Func1<List<String>, Observable<String>>() {  3. @Override  4. public Observable<String> call(List<String> urls) {  5. return Observable.from(urls);  6.         }  7.     })  8.     .subscribe(url -> System.out.println(url));

为了方便您了解发生了什么,我在这里贴出了整个函数代码,使用lambda可以大大简化代码长度:

[java] view plain copy

1. query("Hello, world!")  2.     .flatMap(urls -> Observable.from(urls))  3.     .subscribe(url -> System.out.println(url));

flatMap()看起来奇怪吗?为什么要回到另一个observable?理解flatmap的关键在于,flatmap输出的新observable正是我们想在subscriber中接收的。现在Subscriber不再收到Listtter<String>,相反,收到一些单个字符串,就像Observable一样.from()输出相同。

这部分也是我学RxJava时最难理解的部分。一旦突然意识到,RxJava的很多问题都会一起解决。

还可以更好

flatMap()真的不能更好,它可以返回任何它想要返回的Observable对象。

例如,以下方法:

[java] view plain copy

1. // 回到网站的标题,如果404,回到nulll  2. Observable<String> getTitle(String URL);

然后,在之前的例子中,我现在不想打印URL,而是想打印我收到的每个网站的标题。问题是,我的方法每次只能输入一个URL,返回值不是String,而是输出String的Observabl对象。使用flatMapp可以简单地解决这个问题。

[java] view plain copy

1. query("Hello, world!")  2.     .flatMap(urls -> Observable.from(urls))  3. new Func1<String, Observable<String>>() {  4. @Override  5. public Observable<String> call(String url) {  6. return getTitle(url);  7.         }  8.     })  9.     .subscribe(title -> System.out.println(title));

使用lambda:

[java] view plain copy

1. query("Hello, world!")  2.     .flatMap(urls -> Observable.from(urls))  3.     .flatMap(url -> getTitle(url))  4.     .subscribe(title -> System.out.println(title));

是不是觉得不可思议?我可以把多种独立返回Observable对象的方法结合起来!帅!

不仅如此,我还将两个API的调用组合到一个链式调用中。我们可以调用任何多个API链接。每个人都应该知道同步所有API调用,然后将所有API调用的回调结果组合成需要显示的数据是多么痛苦。在这里,我们成功地避免了callback hell(多层嵌套的回调使代码难以阅读和维护)。现在所有的逻辑都被包装成这个简单的响应调用。

操作符丰富

到目前为止,我们已经接触到两个操作符,RxJava中有更多的操作符,那么我们如何使用其他操作符来改进我们的代码呢?

getTitle()如果url不存在,则返回null。我们不想输出“null“,然后我们可以从返回的title列表中过滤null值!

[java] view plain copy

1. query("Hello, world!")  2.     .flatMap(urls -> Observable.from(urls))  3.     .flatMap(url -> getTitle(url))  4. null)  5.     .subscribe(title -> System.out.println(title));

filter()输出和输入相同的元素,并过滤掉那些不是的元素符合检查条件的。

假如我们最多只想要5个结果:

[java] view plain copy

1. query("Hello, world!")  2.     .flatMap(urls -> Observable.from(urls))  3.     .flatMap(url -> getTitle(url))  4. null)  5. 5)  6.     .subscribe(title -> System.out.println(title));

take()输出最多指定数量的结果。

如果我们想在打印前将每个标题保存到磁盘中:

[java] view plain copy

1. query("Hello, world!")  2.     .flatMap(urls -> Observable.from(urls))  3.     .flatMap(url -> getTitle(url))  4. null)  5. 5)  6.     .doOnNext(title -> saveTitle(title))  7.     .subscribe(title -> System.out.println(title));

doOnNext()允许我们在每次输出元素之前做一些额外的事情,比如这里的保存标题。

看看这里操作数据流有多简单。您可以添加任何更多的操作,而不会扰乱您的代码。

RxJava包含大量的操作符。操作符的数量有点吓人,但值得一个接一个地看,这样你就可以知道哪些操作符可以使用。理解这些操作符可能需要一些时间,但一旦你理解了它们,你就完全掌握了RxJava的力量。

你甚至可以编写自定义操作符!这个blog不打算定制自定义操作符。如果你想,清楚自己的谷歌。

感觉如何?

嗯,你是个怀疑主义者,而且很难被说服,那你为什么要关心这些操作符呢?

因为操作符可以让你操作任何数据流。

链接一系列操作符可以完成复杂的逻辑。代码被分解成一系列可组合的片段。这就是响应函数编程的魅力所在。你使用的越多,你的编程思维就越多。

此外,RxJava还使我们更容易处理数据。在最后一个例子中,我们调用两个API来处理API返回的数据,然后保存到磁盘中。但我们的Subscriber并不知道这一点,它只是认为它正在接收一个Observable<String>对象。良好的包装也给编码带来了便利!

在第三部分,我将介绍RxJava的其他酷特性,如错误处理和并发,这些特性不会直接用于处理数据。

上一篇 ViewPager实现页卡的最新方法--简洁的TabLayout(谷歌支持包)
下一篇 深入浅出RxJava(一:基础篇)

文章素材均来源于网络,如有侵权,请联系管理员删除。

标签: Java教程Java基础Java编程技巧面试题Java面试题