用工厂流水线的方式来理解 RxJava 的概念

简介: 本文讲的是用工厂流水线的方式来理解 RxJava 的概念,已经有很多 RxJava 的文章通过例子阐述了什么是 RxJava 以及怎么去用,但它们大多数只有代码。虽然也会通过类比来解释,例如最出名的就是“流”。通常情况下代码能完美地让人理解
本文讲的是用工厂流水线的方式来理解 RxJava 的概念,

本文已授权微信公众号 AndroidDeveloper 独家发布。

为什么另写一篇 RxJava 的文章?

已经有很多 RxJava 的文章通过例子阐述了什么是 RxJava 以及怎么去用,但它们大多数只有代码。虽然也会通过类比来解释,例如最出名的就是“流”。通常情况下代码能完美地让人理解(我们都是程序员,对吧?),但是 RxJava 十分不同于以往的 Android 开发。在最开始时通过代码是很难让人理解的,用“流”来类比并不足够,即使是 marbles 的例子也还远远不够。我可以保证自己能理解,但对于别人,老实说,难道你们不需要更多结合实际的例子?难道你们不想在脑海中举一个例子来让自己更好地理解 RxJava 吗?我做了,并且我想和你们分享。

工厂流水线

好吧,我说谎了。为了理解 RxJava,我在脑海里举了不仅仅一个例子。例如我尝试观察动物园笼子的动物,尝试观察河流里的鱼,也尝试去观察蝙蝠侠里的犯罪(额,这不是现实生活中的,但不失为一个很好的例子)。但我还是认为工厂流水线是最好的例子。

需求

我们先想象下,我们需要写一款应用来展示动物们的信息,并且现在我需要在新的界面实现以下功能:

  • 三份关于猫的信息
  • 每份都是唯一的
  • 每份都应该少于 300 字符
  • 每份都配张猫的图片

启动流水线!

我们尝试通过流水线上的工人们的帮助实现那些功能。

1. 首先我们需要启动产品处理进程。仅仅有流水线是不足够的 - 还需要有人去启动它。例如一个对结果感兴趣的产品经理

2. 现在我们需要随机获得有关猫的信息。但怎么做呢?幸运的是这里有 API 能让我们很容易做到!真的是巧合么。。。?好吧,我们先通过 GET 方法获取这些信息。

3. 现在我们需要处理来自 API 的响应。它是由 HTTP 状态码和一列有关猫的信息组成。我们并不需要状态码所以我们首先去除它并将信息列表传给下一个工人。

4. 下一件要做的事就是将信息列表的信息一个个抽离出来。为什么要这么做?因为这样做方便下游的工人操作单个字符串(例如检查字符串是否过长)。

5. 每条信息都是唯一的。下一个工人的任务是清除重复项。

6. 每条信息都不能太长(少于 300 字符)

7. 现在我们的信息是唯一的且长度也符合要求可数量太多了而我们仅仅需要 3 份。所以下一个工人应该清除多余的信息。

8. 每条信息都有一张随机的猫的图片。

9. 我们不应该将信息分批给产品经理,而是应该将这些信息打包成一个列表。

10. 现在产品经理可以在屏幕上显示结果了。

这就是我们要做的。我们已经通过流水线上的工人完整地实现了全部功能并最后将结果显示到了屏幕上。

若用 RxJava 实现这些需求该怎么做呢?

RxJava 中存在很多可观察对象(它传出的数据可以被我们观察到)和观察者(它观察并处理可观察对象传出的数据)。在我们的例子里流水线就是可观察对象而产品经理就是观察者。需要注意的是观察者启动整个流水线这个步骤是十分重要的。如果没有观察者,流水线是不会启动的。

那么流水线上的工人算什么呢?在 RxJava 的世界里它们叫做操作符。它们的动作十分像工人 - 他们需要处理那些被传出的数据(例如仅仅让唯一的数据通过)

在代码世界实现流水线

很好。可这么多图片有卵用?代码终究还是代码并不是一条流水线,不是吗?

    mCatFactsService.getCatFacts(100)
                    .map(catFactResponse -> catFactResponse.getFacts())
                    .flatMap(catFacts -> Observable.from(catFacts))
                    .distinct()
                    .filter(catFact -> catFact.length() <= 300)
                    .take(3)
                    .map(catFact -> new CatFactWithImage(catFact, getRandomCatImageId()))
                    .toList()
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(mCatFactsAdapter::setCatFactWithImages, Throwable::printStackTrace);

这样就能通过 RxJava 实现流水线了。为了理解上面的代码你应该从上到下看一遍。每个动作都是独立运行的 - 一个接着一个。

  • mCatFactsService.getCatFacts(100) – 这个就是 GET 方法。在响应里我们获得一个封装了 HTTP 状态码以及一列猫的信息的对象。Observable (即可观察对象)将这个对象(我们叫它 CatFactResponse 吧) 封装起来,现在我们就可以用 RxJava 的操作符对它进行处理。
  • map(), flatMap(), distinct(), filter(), take(), toList() – 这些就是操作符。它们可以修改被传出的数据 - 一个接着一个。它们就像上面例子的图片中流水线上的工人。
  • subscribe() – 让一个 Observer (即观察者)去订阅一个 Observable。若没有这一步整个流水线都无法启动。
  • subscribeOn() – 告诉 Observable 当 subscribe() 方法被调用后它应该在哪个线程被启动。接着每个操作符都会在那个线程工作直到我们改变线程。
  • observeOn() – 改变下一个操作符的工作线程。每个在这个方法之后的操作符都会在它指定的新的线程里工作,直到我们通过别的 observeOn() 改变线程。

现在我们再仔细分析我们用过的每个操作符

    .map(new Func1<CatFactResponse, List<String>>() {
            @Override
            public List<String> call(CatFactResponse catFactResponse) {
                return catFactResponse.getFacts();
            }
    })

有可能你会不适应那花俏的箭头所以我将完整的实现展开了(当然我们可以通过 Java8 的 lambda 表达式实现那种语法 - 详情见 retrolambda 

正如你说看到的, mCatFactsService.getCatFacts() 返回一串数据并被传到 CatFactResponse 中,但因为现在我们不需要 HTTP 状态码,所以我们通过 MAP (转换)操作符将 CatFactResponse 对象转换成别的对象 - 在这个例子中是 List 对象。下一个操作符将会处理这个对象。

    .flatMap(new Func1<List<String>, Observable<? extends String>>() {
            @Override
            public Observable<? extends String> call(List<String> catFacts) {
                return Observable.from(catFacts);
            }
    })

flatMap 操作符接受猫的信息列表作为参数,分别取出列表的每条数据并抛给下一个操作符。所以我们拿到并抛出的数据都是FROM (来自)这个列表的。

    .distinct()

这个操作符用来处理重复项,并且它不会让任何已经通过的相同字符串再次通过。每个都是 DISTINCT (独特的)。

    .filter(new Func1<String, Boolean>() {
            @Override
            public Boolean call(String catFact) {
                return catFact.length() <= 300;
            }
    })

filter 操作符就是个简单的对/错判断表达式。如果字符串太长,将无法通过。所以 filter 很显然是用来 FILTERS (过滤的)。

    .take(3)

take 操作符 TAKES (取出)指定数量的信息。

    .map(new Func1<String, CatFactWithImage>() {
            @Override
            public CatFactWithImage call(String catFact) {
                return new CatFactWithImage(catFact, getRandomCatImageId());
            }
    })

另一个 map 操作符。在我们打包所有字符串之前我们应该为每个字符串添加张猫的图片。

    .toList()

现在我们可以打包所有 CatFactWithImage 对象 TO (成)一个 LIST (列表)了。

    .subscribe(new Observer<List<CatFactWithImage>>() {
            @Override
            public void onCompleted() {
                //no-op
            }

            @Override
            public void onError(Throwable e) {
                e.printStackTrace();
            }

            @Override
            public void onNext(List<CatFactWithImage> catFactWithImages) {
                mCatFactsAdapter.setCatFactWithImages(catFactWithImages);
            }
    });

然后就是简单地将 list 对象传给 adapter 对象而已。

结论

RxJava 是款十分强大的工具。但不幸的是如果你之前没有通过“流”的形式写过代码你可能很难理解它并学会如何去用它。因为它十分不同于以往平常的安卓开发,所以我们需要一些比代码更形象的东西去理解它。我希望这篇文章能帮助你更好地理解 RxJava 是如何工作的。





原文发布时间为:2016年05月11日

本文来自云栖社区合作伙伴掘金,了解相关信息可以关注掘金网站。
目录
相关文章
|
前端开发 算法 测试技术
【软考学习5】流水线基本概念、周期执行时间、吞吐率、加速比和效率的计算
【软考学习5】流水线基本概念、周期执行时间、吞吐率、加速比和效率的计算
942 0
指令流水线——基本概念与性能指标
指令流水线——基本概念与性能指标
415 0
指令流水线——基本概念与性能指标
|
3月前
|
弹性计算 运维 Serverless
项目管理和持续集成系统搭建问题之云效流水线支持阿里云产品的企业用户如何解决
项目管理和持续集成系统搭建问题之云效流水线支持阿里云产品的企业用户如何解决
80 1
项目管理和持续集成系统搭建问题之云效流水线支持阿里云产品的企业用户如何解决
|
3月前
|
敏捷开发 Java 测试技术
阿里云云效产品使用合集之如何下载流水线构建过程中生成的jar
云效作为一款全面覆盖研发全生命周期管理的云端效能平台,致力于帮助企业实现高效协同、敏捷研发和持续交付。本合集收集整理了用户在使用云效过程中遇到的常见问题,问题涉及项目创建与管理、需求规划与迭代、代码托管与版本控制、自动化测试、持续集成与发布等方面。
|
3月前
|
敏捷开发 测试技术 持续交付
阿里云云效产品使用合集之如何限制在本地的构建主机创建的流水线的并发数
云效作为一款全面覆盖研发全生命周期管理的云端效能平台,致力于帮助企业实现高效协同、敏捷研发和持续交付。本合集收集整理了用户在使用云效过程中遇到的常见问题,问题涉及项目创建与管理、需求规划与迭代、代码托管与版本控制、自动化测试、持续集成与发布等方面。
|
3月前
|
敏捷开发 Java 测试技术
阿里云云效产品使用合集之怎么设置流水线中的全局参数
云效作为一款全面覆盖研发全生命周期管理的云端效能平台,致力于帮助企业实现高效协同、敏捷研发和持续交付。本合集收集整理了用户在使用云效过程中遇到的常见问题,问题涉及项目创建与管理、需求规划与迭代、代码托管与版本控制、自动化测试、持续集成与发布等方面。
|
3月前
|
运维 Java Devops
阿里云云效操作报错合集之在流水线增加单元测试报错,是什么导致的
本合集将整理呈现用户在使用过程中遇到的报错及其对应的解决办法,包括但不限于账户权限设置错误、项目配置不正确、代码提交冲突、构建任务执行失败、测试环境异常、需求流转阻塞等问题。阿里云云效是一站式企业级研发协同和DevOps平台,为企业提供从需求规划、开发、测试、发布到运维、运营的全流程端到端服务和工具支撑,致力于提升企业的研发效能和创新能力。
|
3月前
|
缓存 运维 前端开发
阿里云云效操作报错合集之如何解决在使用流水线构建net8应用时遇到无法构建的报错
本合集将整理呈现用户在使用过程中遇到的报错及其对应的解决办法,包括但不限于账户权限设置错误、项目配置不正确、代码提交冲突、构建任务执行失败、测试环境异常、需求流转阻塞等问题。阿里云云效是一站式企业级研发协同和DevOps平台,为企业提供从需求规划、开发、测试、发布到运维、运营的全流程端到端服务和工具支撑,致力于提升企业的研发效能和创新能力。
|
3月前
|
敏捷开发 缓存 5G
阿里云云效产品使用合集之流水线中的webhook是否可以设置为变量
云效作为一款全面覆盖研发全生命周期管理的云端效能平台,致力于帮助企业实现高效协同、敏捷研发和持续交付。本合集收集整理了用户在使用云效过程中遇到的常见问题,问题涉及项目创建与管理、需求规划与迭代、代码托管与版本控制、自动化测试、持续集成与发布等方面。
|
3月前
|
敏捷开发 测试技术 持续交付
阿里云云效产品使用合集之流水线同时并发数最高是多少
云效作为一款全面覆盖研发全生命周期管理的云端效能平台,致力于帮助企业实现高效协同、敏捷研发和持续交付。本合集收集整理了用户在使用云效过程中遇到的常见问题,问题涉及项目创建与管理、需求规划与迭代、代码托管与版本控制、自动化测试、持续集成与发布等方面。

热门文章

最新文章