您的位置:首页 > 编程语言 > Java开发

彻底了解RxJava —— flatMap()

2017-03-09 17:49 316 查看
原文链接

第1部分中,我讨论了RxJava的基本结构,并介绍了map()operator。但是,如果你仍然没有意愿去使用RxJava,我可以理解。因为还你没有大量的工作。但是这将迅速改变–RxJava的大部分功能是包含在在框架中的所有Operators。

让我们通过一个例子向你介绍更多的Operators。

假设

假设我这样一个方法:

// Returns a List of website URLs based on a text search
Observable<List<String>> query(String text);


我想做一个健壮的系统来搜索文本和显示结果。鉴于我们从上一篇文章中知道的,这是可能想出来的:

query("Hello, world!")
.subscribe(urls -> {
for (String url : urls) {
System.out.println(url);
}
});


这个答案令人非常不满意,因为我失去了转换数据流的能力。如果我想修改每个URL,我必须在Subscriber去做,而没有去使用强大的map()处理。

我可以从urls - > urls创建一个map(),但是每个map()调用都会有一个for-each循环。

希望之光

如下的方法,Observable.from()会遍历集合

Observable.from("url1", "url2", "url3")
.subscribe(url -> System.out.println(url));


结合上面的需求

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


确实避免了for-each循环,但是一团糟,有多个嵌套订阅!除了丑陋和难以修改,它也打破了RxJava的一些关键但尚未发现的功能。

更好的方案

flatMap()

Observable.flatMap()获取一个Observable实例,并返回另一个Observable的实例。以下是解决这个问题的方法:

query("Hello, world!")
.flatMap(new Func1<List<String>, Observable<String>>() {
@Override
public Observable<String> call(List<String> urls) {
return Observable.from(urls);
}
})
.subscribe(url -> System.out.println(url));


flatMap()很奇怪,对吧?为什么它返回另一个Observable?这里的关键概念是返回的新Observable是被订阅的。它并没有接收List< String > ,它获得一系列由Observable.from()返回的单个字符串。

甚至更好

flatMap()可以返回任何它想要的Observable

假设我有第二种方法:

// Returns the title of a website, or null if 404
Observable<String> getTitle(String URL);


现在我要打印每个收到的网站的标题,而不是打印网址。但是有一些问题:我的方法一次只处理一个URL,它不返回一个String,它返回一个发出String的Observable。

使用flatMap(),解决这个问题很容易;在将URL列表拆分为单独的项目后,我可以在flatMap()中为每个URL使用getTitle(),然后再到Subscriber:

query("Hello, world!")
.flatMap(urls -> Observable.from(urls))
.flatMap(new Func1<String, Observable<String>>() {
@Override
public Observable<String> call(String url) {
return getTitle(url);
}
})
.subscribe(title -> System.out.println(title));


提升

除了map和flatMap两种operators,还有很多。对上面的操作还可以改进。如果URL是404的时候,getTitle()返回null。

我们不想输出“null”,则可以进行过滤

query("Hello, world!")
.flatMap(urls -> Observable.from(urls))
.flatMap(url -> getTitle(url))
.filter(title -> title != null)
.subscribe(title -> System.out.println(title));


filter 的参数和结果是同一个值,它仅仅对boolean进行判断。

最多显示5个结果,可以这样做

query("Hello, world!")
.flatMap(urls -> Observable.from(urls))
.flatMap(url -> getTitle(url))
.filter(title -> title != null)
.take(5)
.subscribe(title -> System.out.println(title));


take()用于指定最多数量。

保存标题到本地

query("Hello, world!")
.flatMap(urls -> Observable.from(urls))
.flatMap(url -> getTitle(url))
.filter(title -> title != null)
.take(5)
.doOnNext(title -> saveTitle(title))
.subscribe(title -> System.out.println(title));


doOnNext() 可以添加其他动作,针对每个Item。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  RxJava flatMap