在第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。