彻底了解RxJava —— flatMap()

原文链接

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值