上一章中。我们学到怎样转换可观測序列。我们也看到了map(),scan(),groupBY(),以及很多其它实用的函数的实际样例,它们帮助我们操作Observable来创建我们想要的Observable。

本章中,我们将研究组合函数并学习怎样同一时候处理多个Observables来创建我们想要的Observable。

Merge

在异步的世界常常会创建这种场景。我们有多个来源可是仅仅想有一个结果:多输入,单输出。RxJava的merge()方法将帮助你把两个甚至很多其它的Observables合并到他们发射的数据里。下图给出了把两个序列合并在一个终于发射的Observable。

正如你看到的那样,发射的数据被交叉合并到一个Observable里面。

注意假设你同步的合并Observable,它们将连接在一起而且不会交叉。

像通常一样。我们用我们的App和已安装的App列表来创建了一个“真实世界”的样例。我们还须要第二个Observable。我们能够创建一个单独的应用列表然后逆序。当然没有实际的意义,仅仅是为了这个样例。第二个列表,我们的loadList()函数像以下这样:

  1. private void loadList(List<AppInfo> apps) {
  2. mRecyclerView.setVisibility(View.VISIBLE);
  3. List reversedApps = Lists.reverse(apps);
  4. Observable<AppInfo> observableApps =Observable.from(apps);
  5. Observable<AppInfo> observableReversedApps =Observable.from(reversedApps);
  6. Observable<AppInfo> mergedObserbable = Observable.merge(observableApps,observableReversedApps);
  7. mergedObserbable.subscribe(new Observer<AppInfo>(){
  8. @Override
  9. public void onCompleted() {
  10. mSwipeRefreshLayout.setRefreshing(false);
  11. Toast.makeText(getActivity(), "Here is the list!", Toast.LENGTH_LONG).show();
  12. }
  13. @Override
  14. public void onError(Throwable e) {
  15. Toast.makeText(getActivity(), "One of the two Observable threw an error!", Toast.LENGTH_SHORT).show();
  16. mSwipeRefreshLayout.setRefreshing(false);
  17. }
  18. @Override
  19. public void onNext(AppInfoappInfo) {
  20. mAddedApps.add(appInfo);
  21. mAdapter.addApplication(mAddedApps.size() - 1, appInfo);
  22. }
  23. });
  24. }

我们创建了Observable和observableApps数据以及新的observableReversedApps逆序列表。使用Observable.merge(),我们能够创建新的ObservableMergedObservable在单个可观測序列中发射源Observables发出的全部数据。

正如你能看到的,每一个方法签名都是一样的,因此我们的观察者无需在意不论什么不同就能够复用代码。结果例如以下:

注意错误时的toast消息。你能够觉得每一个Observable抛出的错误将会打断合并。假设你须要避免这种情况。RxJava提供了mergeDelayError(),它能从一个Observable中继续发射数据即便是当中有一个抛出了错误。当全部的Observables都完毕时,mergeDelayError()将会发射onError()。例如以下图所看到的:

ZIP

我们在处理多源时可能会带来这样一种场景:多从个Observables接收数据,处理它们。然后将它们合并成一个新的可观測序列来使用。RxJava有一个特殊的方法能够完毕:zip()合并两个或者多个Observables发射出的数据项,依据指定的函数Func*变换它们。并发射一个新值。下图展示了zip()方法怎样处理发射的“numbers”和“letters”然后将它们合并一个新的数据项:

对于“真实世界”的样例来说,我们将使用已安装的应用列表和一个新的动态的Observable来让样例变得有点有趣味。

  1. Observable<Long> tictoc = Observable.interval(1, TimeUnit.SECONDS);

tictocObservable变量使用interval()函数每秒生成一个Long类型的数据:简单且高效。正如之前所说的,我们须要一个Func对象。

由于它须要传两个參数,所以是Func2:

  1. private AppInfo updateTitle(AppInfoappInfo, Long time) {
  2. appInfo.setName(time + " " + appInfo.getName());
  3. return appInfo;
  4. }

如今我们的loadList()函数变成这样:

  1. private void loadList(List<AppInfo> apps) {
  2. mRecyclerView.setVisibility(View.VISIBLE);
  3. Observable<AppInfo> observableApp = Observable.from(apps);
  4. Observable<Long> tictoc = Observable.interval(1, TimeUnit.SECONDS);
  5. Observable.zip(observableApp, tictoc,
  6. (AppInfo appInfo, Long time) -> updateTitle(appInfo, time))
  7. .observeOn(AndroidSchedulers.mainThread())
  8. .subscribe(new Observer<AppInfo>() {
  9. @Override
  10. public void onCompleted() {
  11. Toast.makeText(getActivity(), "Here is the list!", Toast.LENGTH_LONG).show();
  12. }
  13. @Override
  14. public void onError(Throwable e) {
  15. mSwipeRefreshLayout.setRefreshing(false);
  16. Toast.makeText(getActivity(), "Something went wrong!", Toast.LENGTH_SHORT).show();
  17. }
  18. @Override
  19. public void onNext(AppInfoappInfo) {
  20. if (mSwipeRefreshLayout.isRefreshing()) {
  21. mSwipeRefreshLayout.setRefreshing(false);
  22. }
  23. mAddedApps.add(appInfo);
  24. int position = mAddedApps.size() - 1;
  25. mAdapter.addApplication(position, appInfo);
  26. mRecyclerView.smoothScrollToPosition(position);
  27. }
  28. });
  29. }

正如你看到的那样。zip()函数有三个參数:两个Observables和一个Func2

细致一看会发现observeOn()函数。

它将在下一章中解说:如今我们能够小试一下。

结果例如以下:

Join

前面两个方法。zip()merge()方法作用在发射数据的范畴内,在决定怎样操作值之前有些场景我们须要考虑时间的。RxJava的join()函数基于时间窗体将两个Observables发射的数据结合在一起。

为了正确的理解上一张图。我们解释下join()须要的參数:

  • 第二个Observable和源Observable结合。

  • Func1參数:在指定的由时间窗体定义时间间隔内,源Observable发射的数据和从第二个Observable发射的数据相互配合返回的Observable。
  • Func1參数:在指定的由时间窗体定义时间间隔内,第二个Observable发射的数据和从源Observable发射的数据相互配合返回的Observable。
  • Func2參数:定义已发射的数据怎样与新发射的数据项相结合。
  • 例如以下练习的样例。我们能够改动loadList()函数像以下这样:
  1. private void loadList(List<AppInfo> apps) {
  2. mRecyclerView.setVisibility(View.VISIBLE);
  3. Observable<AppInfo> appsSequence =
  4. Observable.interval(1000, TimeUnit.MILLISECONDS)
  5. .map(position -> {
  6. return apps.get(position.intValue());
  7. });
  8. Observable<Long> tictoc = Observable.interval(1000,TimeUnit.MILLISECONDS);
  9. appsSequence.join(
  10. tictoc,
  11. appInfo -> Observable.timer(2,TimeUnit.SECONDS),
  12. time -> Observable.timer(0, TimeUnit.SECONDS),
  13. this::updateTitle)
  14. .observeOn(AndroidSchedulers.mainThread())
  15. .take(10)
  16. .subscribe(new Observer<AppInfo>() {
  17. @Override
  18. public void onCompleted() {
  19. Toast.makeText(getActivity(), "Here is the list!", Toast.LENGTH_LONG).show();
  20. }
  21. @Override
  22. public void onError(Throwable e) {
  23. mSwipeRefreshLayout.setRefreshing(false);
  24. Toast.makeText(getActivity(), "Something went wrong!", Toast.LENGTH_SHORT).show();
  25. }
  26. @Override
  27. public void onNext(AppInfoappInfo) {
  28. if (mSwipeRefreshLayout.isRefreshing()) {
  29. mSwipeRefreshLayout.setRefreshing(false);
  30. }
  31. mAddedApps.add(appInfo);
  32. int position = mAddedApps.size() - 1;
  33. mAdapter.addApplication(position, appInfo);
  34. mRecyclerView.smoothScrollToPosition(position);
  35. }
  36. });
  37. }

我们有一个新的对象appsSequence,它是一个每秒从我们已安装的app列表发射app数据的可观測序列。

tictoc这个Observable数据每秒仅仅发射一个新的Long型整数。为了合并它们,我们须要指定两个Func1变量:

  1. appInfo -> Observable.timer(2, TimeUnit.SECONDS)
  2. time -> Observable.timer(0, TimeUnit.SECONDS)

上面描写叙述了两个时间窗体。

以下一行描写叙述我们怎样使用Func2将两个发射的数据结合在一起。

  1. this::updateTitle

结果例如以下:

它看起来有点乱,可是注意app的名字和我们指定的时间窗体,我们能够看到:一旦第二个数据发射了我们就会将它与源数据结合,但我们用同一个源数据有2秒钟。这就是为什么标题反复数字累加的原因。

值得一提的是,为了简单起见,也有一个join()操作符作用于字符串然后简单的和发射的字符串连接成终于的字符串。

combineLatest

RxJava的combineLatest()函数有点像zip()函数的特殊形式。

正如我们已经学习的,zip()作用于近期未打包的两个Observables。相反。combineLatest()作用于近期发射的数据项:假设Observable1发射了A而且Observable2发射了B和C,combineLatest()将会分组处理AB和AC,例如以下图所看到的:

combineLatest()函数接受二到九个Observable作为參数,假设有须要的话或者单个Observables列表作为參数。

从之前的样例中把loadList()函数借用过来,我们能够改动一下来用于combineLatest()实现“真实世界”这个样例:

  1. private void loadList(List<AppInfo> apps) {
  2. mRecyclerView.setVisibility(View.VISIBLE);
  3. Observable<AppInfo> appsSequence = Observable.interval(1000, TimeUnit.MILLISECONDS)
  4. .map(position ->apps.get(position.intValue()));
  5. Observable<Long> tictoc = Observable.interval(1500, TimeUnit.MILLISECONDS);
  6. Observable.combineLatest(appsSequence, tictoc,
  7. this::updateTitle)
  8. .observeOn(AndroidSchedulers.mainThread())
  9. .subscribe(new Observer<AppInfo>() {
  10. @Override
  11. public void onCompleted() {
  12. Toast.makeText(getActivity(), "Here is the list!", Toast.LENGTH_LONG).show();
  13. }
  14. @Override
  15. public void onError(Throwable e) {
  16. mSwipeRefreshLayout.setRefreshing(false);
  17. Toast.makeText(getActivity(), "Something went wrong!", Toast.LENGTH_SHORT).show();
  18. }
  19. @Override
  20. public void onNext(AppInfoappInfo) {
  21. if (mSwipeRefreshLayout.isRefreshing()) {
  22. mSwipeRefreshLayout.setRefreshing(false);
  23. }
  24. mAddedApps.add(appInfo);
  25. int position = mAddedApps.size() - 1;
  26. mAdapter.addApplication(position, appInfo);
  27. mRecyclerView.smoothScrollToPosition(position);
  28. }
  29. });
  30. }

这我们使用了两个Observables:一个是每秒钟从我们已安装的应用列表发射一个App数据,第二个是每隔1.5秒发射一个Long型整数。

我们将他们结合起来并运行updateTitle()函数,结果例如以下:

正如你看到的。由于不同的时间间隔,AppInfo对象如我们所预料的那样有时候会反复。

And,Then和When

在将来另一些zip()满足不了的场景。

如复杂的架构,或者是仅仅为了个人爱好。你能够使用And/Then/When解决方式。

它们在RxJava的joins包下,使用Pattern和Plan作为中介,将发射的数据集合并到一起。

我们的loadList()函数将会被改动从这样:

  1. private void loadList(List<AppInfo> apps) {
  2. mRecyclerView.setVisibility(View.VISIBLE);
  3. Observable<AppInfo> observableApp = Observable.from(apps);
  4. Observable<Long> tictoc = Observable.interval(1, TimeUnit.SECONDS);
  5. Pattern2<AppInfo, Long> pattern = JoinObservable.from(observableApp).and(tictoc);
  6. Plan0<AppInfo> plan = pattern.then(this::updateTitle);
  7. JoinObservable
  8. .when(plan)
  9. .toObservable()
  10. .observeOn(AndroidSchedulers.mainThread())
  11. .subscribe(new Observer<AppInfo>() {
  12. @Override
  13. public void onCompleted() {
  14. Toast.makeText(getActivity(), "Here is the list!", Toast.LENGTH_LONG).show();
  15. }
  16. @Override
  17. public void onError(Throwable e) {
  18. mSwipeRefreshLayout.setRefreshing(false);
  19. Toast.makeText(getActivity(), "Something went wrong!", Toast.LENGTH_SHORT).show();
  20. }
  21. @Override
  22. public void onNext(AppInfoappInfo) {
  23. if (mSwipeRefreshLayout.isRefreshing()) {
  24. mSwipeRefreshLayout.setRefreshing(false);
  25. }
  26. mAddedApps.add(appInfo);
  27. int position = mAddedApps.size() - 1;
  28. mAdapter.addApplication(position, appInfo); mRecyclerView.smoothScrollToPosition(position);
  29. }
  30. });
  31. }

和通常一样。我们有两个发射的序列。observableApp,发射我们安装的应用列表数据。tictoc每秒发射一个Long型整数。如今我们用and()连接源Observable和第二个Observable。

  1. JoinObservable.from(observableApp).and(tictoc);

这里创建一个pattern对象,使用这个对象我们能够创建一个Plan对象:”我们有两个发射数据的Observables,then()是做什么的?”

  1. pattern.then(this::updateTitle);

如今我们有了一个Plan对象而且当plan发生时我们能够决定接下来发生的事情。

  1. .when(plan).toObservable()

这时候,我们能够订阅新的Observable,正如我们总是做的那样。

Switch

有这样一个复杂的场景就是在一个subscribe-unsubscribe的序列里我们能够从一个Observable自己主动取消订阅来订阅一个新的Observable。

RxJava的switch(),正如定义的,将一个发射多个Observables的Observable转换成另一个单独的Observable。后者发射那些Observables近期发射的数据项。

给出一个发射多个Observables序列的源Observable,switch()订阅到源Observable然后開始发射由第一个发射的Observable发射的一样的数据。当源Observable发射一个新的Observable时,switch()马上取消订阅前一个发射数据的Observable(因此打断了从它那里发射的数据流)然后订阅一个新的Observable,并開始发射它的数据。

StartWith

我们已经学到怎样连接多个Observables并追加指定的值到一个发射序列里。

RxJava的startWith()concat()的相应部分。正如concat()向发射数据的Observable追加数据那样,在Observable開始发射他们的数据之前。 startWith()通过传递一个參数来先发射一个数据序列。

总结

这章中。我们学习了怎样将两个或者很多其它个Observable结合来创建一个新的可观測序列。

我们将能够merge Observable。join Observables 。zip Observables 并在几种情况下把他们结合在一起。

下一章。我们将介绍调度器,它将非常easy的帮助我们创建主线程以及提高我们应用程序的性能。我们也将学习怎样正确的运行长任务或者I/O任务来获得更好的性能。

RxJava开发精要6 - 组合Observables的更多相关文章

  1. RxJava开发精要6 – Observables组合

    原文出自<RxJava Essentials> 原文作者 : Ivan Morgillo 译文出自 : 开发技术前线 www.devtf.cn 转载声明: 本译文已授权开发者头条享有独家转 ...

  2. RxJava开发精要5 – Observables变换

    原文出自<RxJava Essentials> 原文作者 : Ivan Morgillo 译文出自 : 开发技术前线 www.devtf.cn 转载声明: 本译文已授权开发者头条享有独家转 ...

  3. RxJava开发精要4 – Observables过滤

    原文出自<RxJava Essentials> 原文作者 : Ivan Morgillo 译文出自 : 开发技术前线 www.devtf.cn 转载声明: 本译文已授权开发者头条享有独家转 ...

  4. RxJava开发精要2-为什么是Observables?

    原文出自<RxJava Essentials> 原文作者 : Ivan Morgillo 译文出自 : 开发技术前线 www.devtf.cn 转载声明: 本译文已授权开发者头条享有独家转 ...

  5. RxJava开发精要1-从.NET到RxJava

    原文出自<RxJava Essentials> 原文作者 : Ivan Morgillo 译文出自 : 开发技术前线 www.devtf.cn 转载声明: 本译文已授权开发者头条享有独家转 ...

  6. RxJava开发精要7 – Schedulers-解决Android主线程问题

    原文出自<RxJava Essentials> 原文作者 : Ivan Morgillo 译文出自 : 开发技术前线 www.devtf.cn 转载声明: 本译文已授权开发者头条享有独家转 ...

  7. RxJava开发精要3-向响应式世界问好

    原文出自<RxJava Essentials> 原文作者 : Ivan Morgillo 译文出自 : 开发技术前线 www.devtf.cn 转载声明: 本译文已授权开发者头条享有独家转 ...

  8. RxJava开发精要8 – 与REST无缝结合-RxJava和Retrofit

    原文出自<RxJava Essentials> 原文作者 : Ivan Morgillo 译文出自 : 开发技术前线 www.devtf.cn 转载声明: 本译文已授权开发者头条享有独家转 ...

  9. RxJava学习笔记(组合Observables)(转)

    组合Observable 当我们需要处理多个Observable的时候,我们可以通过Rxjava的组合函数来创建我们自己想要的Observable. Merge RxJava的 merge() 方法将 ...

随机推荐

  1. defaultView and parentWindow

    defaultView     只读的 which is used to represent the currently rendered view of the document 返回的值通常是包含 ...

  2. Java面试常会被问到的经典面试题,学习或者求职,你都要好好掌握

    Java现在的热度虽然有所下降,但是,学Java的人依旧很多..Java的岗位也是渗透很多.那么,那些经典的Java知识点,你能看到问题就能说出一二三吗?来一起看看.. 1.JDK和JRE的区别 2. ...

  3. Windows系统下python3中安装pyMysql

    python2和python3是不兼容的,在py2中,链接数据库使用的是mysqldb,但在py3中是不能用的. 解决办法就是在py3中数据库使用的模块是pyMysql. 在dos窗口中安装第三方库会 ...

  4. no suitable driver found for jdbc:mysql//localhost:3306/..

      出现这样的情况,一般有四种原因(网上查的): 一:连接URL格式出现了问题(Connection conn=DriverManager.getConnection("jdbc:mysql ...

  5. 手工搭建基于ABP的框架(2) - 访问数据库

    为了防止不提供原网址的转载,特在这里加上原文链接: http://www.cnblogs.com/skabyy/p/7517397.html 本篇我们实现数据库的访问.我们将实现两种数据库访问方法来访 ...

  6. 机器学习,安装python的支持包

    windows10,64位: 以下命令行安装均在python目录下,对应的whl文件也被我拷贝到python目录下: http://www.lfd.uci.edu/~gohlke/pythonlibs ...

  7. HTML+CSS+js常见知识点

    一.HTML.CSS常见知识点 1.垂直居中盒子 /* 方法一 */ html, body { width: 100%; height: 100%; padding: 0; margin: 0; } ...

  8. MyEclipse10激活方法

    背景:因为以前一直使用的是myeclipse8.6版本,但因为版本太低有些功能不支持,于是想试用下myeclipse10.0版本,但是下载后发现需要激活,但在激活的过程中遇到了很多坑,于是便有了本文的 ...

  9. [S]SQL SERVER数据库维护与重建索引

    第一步:查看是否需要维护,查看扫描密度/Scan Density是否为100% declare @table_id int set @table_id=object_id('表名') dbcc sho ...

  10. flask + Python3 实现的的API自动化测试平台---- IAPTest接口测试平台

    **背景: 1.平时测试接口,总是现写代码,对测试用例的管理,以及测试报告的管理持久化做的不够,              2.工作中移动端开发和后端开发总是不能并行进行,需要一个mock的依赖来让他 ...