zoukankan      html  css  js  c++  java
  • 理解RxJava:(二)Operator,Operator

    第一部分,我讲解了RxJava的基本结构,也介绍了map()操作。然而,我能理解你仍旧不会选择使用Rxjava——你仍然还有很多东西没有学到。但是这个情况将很快得到改变。Rxjava一大部分的能力是因为其中的operators。

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

    初始

    假设我有一个这样的方法:

    //返回一个基于文本查询网站链接的列表
    Observable<List<String>> query(String text); 
    

    我想要构建一个搜索文本和显示结果的强健系统。基于上篇文章我们学到的,以下是我们马上想到的:

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

    这个答案让人非常不满意,因为失去了转换数据流的能力。如果我想要修改每个URL,只能在每个Subscriber里面修改。这就违背了使用map()操作的初衷。

    我可以为ulrs->urls创建一个map(),但是每个map()的内部都有一个for-each循环。哎哟。

    一线希望

    有一个方法,Observable.from(),输入一些items,然后每次发出一个:

    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的一些原则。

    更好的方法

    屏住你的呼吸,因为你见到了你的救世主: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));
    
    

    我写成完整的方法是为了你能看到发生了什么,但是用 lambda表达式简写看起来很棒:

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

    flatMap()(看起来)很怪,对吗?为什么返回另一个Observable?核心概念是新的Observable返回的正是Subscriber所观察的。它不接收List<String>——它接收Observable.from()返回的一系列的单独的Strings

    此外

    我强调这个观点几遍都不足够:flatMap()能返回任意想要的Observable

    假设我又有一个这样的方法:

    // 返回网站的标题,若是404则返回null
    Observable<String> getTitle(String URL);
    

    原本是打印URL,现在我想要打印接收的每个网站的标题。但是有些问题:我的方法只对每次一个URL有效,而且它返回的不是String,它返回的是发出String的Observable

    有了flatMap(),解决这个问题很简单。在把一系列的URL分开为单独的items后,我可以在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));
    
    

    同样,使用lambda简写:

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

    很酷,对吧?我把几个返回Observable方法组合在一起。

    不仅仅于此,我还将两个API调用组合在一条方法链上了。你们知道维持所有的API调用同步,必须在数据展示前将它们的回调写在一起,是有多痛苦?我们不用再忍受嵌套回调了。所有的逻辑都包在简短的响应式调用中了。

    大量的Operators

    到目前为止,我们仅仅学习了两种operators。有很多还没有学到。其他的operators能怎样改善我们的代码呢?

    getTitle()在URL404的时候返回null。我们不想要输出"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()方法发出和它们接收到的同样的item,只在通过了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()最多发出指定数量的item(如果少于5个标题,它会提前停止)。

    现在我们想要存储每个标题到磁盘上:

    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有非常多的Operators。这么多operators让我们被吓到,但是值得查阅一遍以知道哪个对我们有用。消化这些操作会花费点时间,但是我们能信手拈来的时候就能感受到Rxjava真正的强大。

    以上都是官方提供的,我们甚至可以自定义operators!这超出了本文的讨论范围。但是只要你想你就能做到。

    So What?

    如果你是个怀疑论者。你会问为什么要关注这些operators?

    关键点3 Operators让你能对数据流做任何事

    唯一的限制就是你自己。

    你可以处理复杂的逻辑,从使用简单的operators链开始。它将你的代码打破为可重组的零碎东西。这就是函数响应式编程。你用的越多,就越能改变你编程的思维。

    另外,想想我们的代码一转换消费起来变得多容易。最后的例子,我们调用了两次API,操作数据,然后存储。但是Subscriber并不知道这些。它想的仅仅是消费Observable<String>。封装让编程更简单。

    在第三部分,我们将继续了解RxJava的特性。比如错误处理和并发,和操作数据没有直接联系。

    本文翻译自Grokking RxJava, Part 2: Operator Operator,著作权归原作者danlew所有。译文由JohnTsai翻译。转载请注明出处,并保留此段声明。

  • 相关阅读:
    BeanUtils.copyProperties的用法
    Eclipse中GitLab的配置和使用入门
    认识与入门 Markdown
    mybatis基础配置
    动态规划-最长公共子串
    查找
    Entity Framework Code First ---EF Power Tool 和MySql一起使用遇到的问题
    使用TortoiseSVN碰到的几个问题(2)-冲突解决, 图标重载
    使用TortoiseSVN碰到的几个问题(1)-导入,提交,更新
    Asp.net MVC4 Step By Step(5)-使用Web API
  • 原文地址:https://www.cnblogs.com/JohnTsai/p/5700120.html
Copyright © 2011-2022 走看看