了解RxJava之操作符(二)

来源:互联网 发布:淘宝琪琪家园怎么样 编辑:程序博客网 时间:2024/06/18 04:05

原文链接:Grokking RxJava, Part 2: Operator, Operator

在第一部分中我浏览了RxJava的基本结构,并且介绍了map操作符。我理解你仍旧没十足的意愿使用RxJava,因为你目前只是了解的一点点。但是看过接下来这么文章就会有所改变,RxJava框架的强大之处在于包含了大量的操作符。

让我通过例子,介绍更多的操作符。

0x00 初始工作

假设有这样一个方法,通过输入内容获取一个URLs列表:

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

我希望构建一个强大的系统,用于查询输入内容并显示查询结果。根据上一篇文章的知识,可能写作这样的代码:

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

这个作品完全不尽如人意,以至于失去了修改数据流的能力。如果我希望修改每一个URL,我不得不在Subscriber处理全部的列表。怎么能忘记酷炫的map()操作符呢!

我加入map操作符,但是要处理的还是URLs列表,在内部还是不能摆脱for-each循环。

0x01 一线希望

有个一个方法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循环,但是这份代码是丑陋的,产生了多个嵌套的subscriptions ,除了丑陋和难已修改,还破坏了接下来还每一提到了RxJava的特性。

0x02 改进

救星来了,屏住呼吸:flatMap()

flatMap将一个发射数据的Observable变换为都个Observables,然后将它们发射的数据合并后放在一个单独的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));

使用lambda表达式简化:

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

flatMap()有点怪,对吗?为什么它会返回另一个Observable?这里的关键概念是,新的可观察到的返回是Subscriber要看到的。Subscriber不再收到List,而是收到一系列单独的字符串,就像Observable.from()。

这里对应我来说,比较难以理解。但是一旦顿悟,就飞上云霄。

0x03 还可以更好

不得不强调,flapMap()可以返回任何的Observable。

假设有下面这样的方法:

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

现在我不想打印URLs列表,我希望打印一个网站的标题。但是遇到一个问题,这个方法之一次只接受一个URL,并且返回的是发射字符串的Observable,而不是字符串。

通过flatMap(),很容易解决这个问题:

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));

使用lambda表达式简化:

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

觉得不可思议,对吗?我将多个独立的Observable组合成一个Observables。太酷了!

不止于此,请注意我组合了两个API的链式调用。当然,我可以组合任意数量的API调用。想想回调地狱吧,现在的逻辑多么简单。

0x04 丰富的操作符

目前,我们只接触两个操作符,还有很多没有接触的。我们怎么样改善我们的代码呢?

如果访问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()不改变发出的数据,只发射通过布尔检查的数据

下面只想要显示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()发出指定数量的事件。(在本例中,如果标题数量少于5个,Observable会提前停止)。

现在我们希望同时在磁盘上保存每一个结果:

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()允许我们在发出事件后添加额外的行为,在本例就是保存标题。

你已经注意到操作数据流是多么的容易!你可以加入更多的操作,程序还不会混乱。

RxJava包含大量的操作符。虽然多的吓人,但是我们值得了解每一个操作符。一旦你知道操作符的使用场景,你就能将操作符转化为真正的力量。

在这些操作符之外,你甚至可以编写自己的操作符。这已经超出本文的范围,基本上只有你想不到的,没有做不到的。

0x05 感觉怎样?

如果这些还不能决心使用RxJava,那你又为什么关心每一个操作符呢?

主要理念3:操作符可以对数据流做任何事。
唯一的限制就在于你自己

你可以通过响应式简化复杂的逻辑。RxJava可以复杂的程序分解为可以组合的片段,这就是响应式编程的魅力。随着你对RxJava的了解,你会为它所折服。

在第三部分,我将介绍RxJava的其他特性,如错误处理和并发性。
另外,想想这多么简化了数据最终的消费形式。在例子最后,我通过两个API调用,修改数据并保存在磁盘。但是Subscriber并不了解这些,它最终只消费Observable。封装简化编程。

0 0
原创粉丝点击