这一章我们接着介绍组合操作符,这类operators可以同时处理多个Observable来创建我们所需要的Observable。组合操作符主要包含: Merge StartWith Concat Zip CombineLatest SwitchOnNext Join等等。

Merge

merge(Observable, Observable)将两个Observable发射的事件序列组合并成一个事件序列,就像是一个Observable发射的一样。你可以简单的将它理解为两个Obsrvable合并成了一个Observable,合并后的数据是无序的。

我们看下面的例子,一共有两个Observable:一个用来发送字母,另一个用来发送数字;现在我们需要两连个Observable发射的数据合并。

String[] letters = new String[]{"A", "B", "C", "D", "E", "F", "G", "H"};
Observable<String> letterSequence = Observable.interval(300, TimeUnit.MILLISECONDS)
.map(new Func1<Long, String>() {
@Override
public String call(Long position) {
return letters[position.intValue()];
}
}).take(letters.length); Observable<Long> numberSequence = Observable.interval(500, TimeUnit.MILLISECONDS).take(5); Observable.merge(letterSequence, numberSequence)
.subscribe(new Observer<Serializable>() {
@Override
public void onCompleted() {
System.exit(0);
} @Override
public void onError(Throwable e) {
System.out.println("Error:" + e.getMessage());
} @Override
public void onNext(Serializable serializable) {
System.out.print(serializable.toString()+" ");
}
});

程序输出:

A 0 B C 1 D E 2 F 3 G H 4

merge(Observable[])将多个Observable发射的事件序列组合并成一个事件序列,就像是一个Observable发射的一样。

StartWith

startWith(T)用于在源Observable发射的数据前插入数据。使用startWith(Iterable<T>)我们还可以在源Observable发射的数据前插入Iterable。官方示意图:

)" title="">

startWith(Observable<T>)用于在源Observable发射的数据前插入另一个Observable发射的数据(这些数据会被插入到

源Observable发射数据的前面)。官方示意图:

)" title="">

Concat

concat(Observable<? extends T>, Observable<? extends T>) concat(Observable<? extends Observable<T>>)用于将多个obserbavle发射的的数据进行合并发射,concat严格按照顺序发射数据,前一个Observable没发射玩是不会发射后一个Observable的数据的。它和merge、startWitch和相似,不同之处在于:

  1. merge:合并后发射的数据是无序的;
  2. startWitch:只能在源Observable发射的数据前插入数据。

, Observable)、concat(Observable>)" title="">

这里我们将前面Merge操作符的例子拿过来,并将操作符换成Concat,然后我们看看执行结果:

String[] letters = new String[]{"A", "B", "C", "D", "E", "F", "G", "H"};
Observable<String> letterSequence = Observable.interval(300, TimeUnit.MILLISECONDS)
.map(new Func1<Long, String>() {
@Override
public String call(Long position) {
return letters[position.intValue()];
}
}).take(letters.length); Observable<Long> numberSequence = Observable.interval(500, TimeUnit.MILLISECONDS).take(5); Observable.concat(letterSequence, numberSequence)
.subscribe(new Observer<Serializable>() {
@Override
public void onCompleted() {
System.exit(0);
} @Override
public void onError(Throwable e) {
System.out.println("Error:" + e.getMessage());
} @Override
public void onNext(Serializable serializable) {
System.out.print(serializable.toString() + " ");
}
});

程序输出:

A B C D E F G H 0 1 2 3 4

Zip

zip(Observable, Observable, Func2)用来合并两个Observable发射的数据项,根据Func2函数生成一个新的值并发射出去。当其中一个Observable发送数据结束或者出现异常后,另一个Observable也将停在发射数据。

和前面的例子一样,我们将操作符换成了zip:

String[] letters = new String[]{"A", "B", "C", "D", "E", "F", "G", "H"};
Observable<String> letterSequence = Observable.interval(120, TimeUnit.MILLISECONDS)
.map(new Func1<Long, String>() {
@Override
public String call(Long position) {
return letters[position.intValue()];
}
}).take(letters.length); Observable<Long> numberSequence = Observable.interval(200, TimeUnit.MILLISECONDS).take(5); Observable.zip(letterSequence, numberSequence, new Func2<String, Long, String>() {
@Override
public String call(String letter, Long number) {
return letter + number;
}
}).subscribe(new Observer<String>() {
@Override
public void onCompleted() {
System.exit(0);
} @Override
public void onError(Throwable e) {
System.out.println("Error:" + e.getMessage());
} @Override
public void onNext(String result) {
System.out.print(result + " ");
}
});

程序输出:

A0 B1 C2 D3 E4

CombineLatest

comnineLatest(Observable, Observable, Func2)用于将两个Observale最近发射的数据已经Func2函数的规则进展组合。下面是官方提供的原理图:

下面这张图应该更容易理解:

List<String> communityNames = DataSimulator.getCommunityNames();
List<Location> locations = DataSimulator.getLocations(); Observable<String> communityNameSequence = Observable.interval(1, TimeUnit.SECONDS)
.map(new Func1<Long, String>() {
@Override
public String call(Long position) {
return communityNames.get(position.intValue());
}
}).take(communityNames.size());
Observable<Location> locationSequence = Observable.interval(1, TimeUnit.SECONDS)
.map(new Func1<Long, Location>() {
@Override
public Location call(Long position) {
return locations.get(position.intValue());
}
}).take(locations.size()); Observable.combineLatest(
communityNameSequence,
locationSequence,
new Func2<String, Location, String>() {
@Override
public String call(String communityName, Location location) {
return "小区名:" + communityName + ", 经纬度:" + location.toString();
}
}).subscribe(new Observer<String>() {
@Override
public void onCompleted() {
System.exit(0);
} @Override
public void onError(Throwable e) {
System.out.println("Error:" + e.getMessage());
} @Override
public void onNext(String s) {
System.out.println(s);
}
});

程序输出:

小区名:竹园新村, 经纬度:(21.827, 23.323)
小区名:康桥半岛, 经纬度:(21.827, 23.323)
小区名:康桥半岛, 经纬度:(11.923, 16.309)
小区名:中粮·海景壹号, 经纬度:(11.923, 16.309)
小区名:中粮·海景壹号, 经纬度:(22.273, 53.623)
小区名:浦江名苑, 经纬度:(22.273, 53.623)
小区名:南辉小区, 经纬度:(22.273, 53.623)

SwitchOnNext

switchOnNext(Observable<? extends Observable<? extends T>>用来将一个发射多个小Observable的源Observable转化为一个Observable,然后发射这多个小Observable所发射的数据。如果一个小的Observable正在发射数据的时候,源Observable又发射出一个新的小Observable,则前一个Observable发射的数据会被抛弃,直接发射新

的小Observable所发射的数据。

结合下面的原理图大家应该很容易理解,我们可以看到下图中的黄色圆圈就被丢弃了。

>)" title="">

Join

join(Observable, Func1, Func1, Func2)我们先介绍下join操作符的4个参数:

  • Observable:源Observable需要组合的Observable,这里我们姑且称之为目标Observable;
  • Func1:接收从源Observable发射来的数据,并返回一个Observable,这个Observable的声明周期决定了源Obsrvable发射出来的数据的有效期;
  • Func1:接收目标Observable发射来的数据,并返回一个Observable,这个Observable的声明周期决定了目标Obsrvable发射出来的数据的有效期;
  • Func2:接收从源Observable和目标Observable发射出来的数据,并将这两个数据组合后返回。

所以Join操作符的语法结构大致是这样的:onservableA.join(observableB, 控制observableA发射数据有效期的函数, 控制observableB发射数据有效期的函数,两个observable发射数据的合并规则)

join操作符的效果类似于排列组合,把第一个数据源A作为基座窗口,他根据自己的节奏不断发射数据元素,第二个数据源B,每发射一个数据,我们都把它和第一个数据源A中已经发射的数据进行一对一匹配;举例来说,如果某一时刻B发射了一个数据“B”,此时A已经发射了0,1,2,3共四个数据,那么我们的合并操作就会把“B”依次与0,1,2,3配对,得到四组数据: [0, B] [1, B] [2, B] [3, B]

再看看下面的图是不是好理解了呢?!

读懂了上面的文字,我们再来写段代码加深理解。

final List<House> houses = DataSimulator.getHouses();//模拟的房源数据,用于测试

//用来每秒从houses总取出一套房源并发射出去
Observable<House> houseSequence =
Observable.interval(1, TimeUnit.SECONDS)
.map(new Func1<Long, House>() {
@Override
public House call(Long position) {
return houses.get(position.intValue());
}
}).take(houses.size());//这里的take是为了防止houses.get(position.intValue())数组越界 //用来实现每秒发送一个新的Long型数据
Observable<Long> tictoc = Observable.interval(1, TimeUnit.SECONDS); houseSequence.join(tictoc,
new Func1<House, Observable<Long>>() {
@Override
public Observable<Long> call(House house) {
return Observable.timer(2, TimeUnit.SECONDS);
}
},
new Func1<Long, Observable<Long>>() {
@Override
public Observable<Long> call(Long aLong) {
return Observable.timer(0, TimeUnit.SECONDS);
}
},
new Func2<House, Long, String>() {
@Override
public String call(House house, Long aLong) {
return aLong + "-->" + house.getDesc();
}
}
).subscribe(new Observer<String>() {
@Override
public void onCompleted() {
System.exit(0);
} @Override
public void onError(Throwable e) {
System.out.println("Error:"+e.getMessage());
} @Override
public void onNext(String s) {
System.out.println(s);
}
});

程序输出:

0-->中粮海景壹号新出大平层!总价4500W起
1-->中粮海景壹号新出大平层!总价4500W起
1-->满五唯一,黄金地段
2-->中粮海景壹号新出大平层!总价4500W起
2-->满五唯一,黄金地段
2-->一楼自带小花园
3-->一楼自带小花园
3-->毗邻汤臣一品
4-->毗邻汤臣一品
4-->顶级住宅,给您总统般尊贵体验
5-->顶级住宅,给您总统般尊贵体验
5-->顶层户型,两室一厅
6-->顶层户型,两室一厅
6-->南北通透,豪华五房
7-->南北通透,豪华五房

通过转换操作符过滤操作符组合操作符三个篇幅将RxJava主要的操作符也介绍的七七八八了。更多操作符的介绍建议大家去查阅官方文档,并自己动手实践一下。这一系列的文章也会持续更新,欢迎大家保持关注!:)

Demo源码地址:https://github.com/BaronZ88/HelloRxJava

如果你喜欢我的文章,就关注下我的知乎专栏或者在 GitHub 上添个 Star 吧!

RxJava系列5(组合操作符)的更多相关文章

  1. RxJava系列4(过滤操作符)

    RxJava系列1(简介) RxJava系列2(基本概念及使用介绍) RxJava系列3(转换操作符) RxJava系列4(过滤操作符) RxJava系列5(组合操作符) RxJava系列6(从微观角 ...

  2. RxJava系列3(转换操作符)

    RxJava系列1(简介) RxJava系列2(基本概念及使用介绍) RxJava系列3(转换操作符) RxJava系列4(过滤操作符) RxJava系列5(组合操作符) RxJava系列6(从微观角 ...

  3. RxJava系列番外篇:一个RxJava解决复杂业务逻辑的案例

    之前写过一系列RxJava的文章,也承诺过会尽快有RxJava2的介绍.无奈实际项目中还未真正的使用RxJava2,不敢妄动笔墨.所以这次还是给大家分享一个使用RxJava1解决问题的案例,希望对大家 ...

  4. RxJava系列7(最佳实践)

    RxJava系列1(简介) RxJava系列2(基本概念及使用介绍) RxJava系列3(转换操作符) RxJava系列4(过滤操作符) RxJava系列5(组合操作符) RxJava系列6(从微观角 ...

  5. RxJava系列6(从微观角度解读RxJava源码)

    RxJava系列1(简介) RxJava系列2(基本概念及使用介绍) RxJava系列3(转换操作符) RxJava系列4(过滤操作符) RxJava系列5(组合操作符) RxJava系列6(从微观角 ...

  6. RxJava系列2(基本概念及使用介绍)

    RxJava系列1(简介) RxJava系列2(基本概念及使用介绍) RxJava系列3(转换操作符) RxJava系列4(过滤操作符) RxJava系列5(组合操作符) RxJava系列6(从微观角 ...

  7. RxJava系列1(简介)

    RxJava系列1(简介) RxJava系列2(基本概念及使用介绍) RxJava系列3(转换操作符) RxJava系列4(过滤操作符) RxJava系列5(组合操作符) RxJava系列6(从微观角 ...

  8. RxJava系列之二 变换类操作符具体解释1

    1.回想 上一篇文章我们主要介绍了RxJava , RxJava 的Observables和 RxJava的just操作符.以及RxJava一些经常使用的操作. 没看过的抓紧点我去看吧. 事实上RxJ ...

  9. RxJava【过滤】操作符 filter distinct throttle take skip first MD

    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...

随机推荐

  1. python作业01

    1.编译型语言在应用源执行前,需要先通过编译将程序源代码翻译为可被硬件平台直接运维的二进制机器码,编译好的二进制执行文件仅能在对应平台运行.因此不依赖解释器,执行效率高,跨平台性差.常见的编译型语言: ...

  2. 一些常见的shell命令和git命令

    shell命令: pwd : (Print Working Directory) 查看当前目录 cd (Change Directory) 切换目录,如 cd /etc ./当前目录  ../上级目录 ...

  3. 跨域的另一种解决方案CORS(CrossOrigin Resource Sharing)跨域资源共享

    在我们日常的项目开发时使用AJAX,传统的Ajax请求只能获取在同一个域名下面的资源,但是HTML5打破了这个限制,允许Ajax发起跨域的请求.浏览器是可以发起跨域请求的,比如你可以外链一个外域的图片 ...

  4. NodeJS FTP模块使用

    模块说明:https://www.npmjs.com/package/ftp 上传文件 建立连接-> 判断文件夹是否存在->创建文件夹->上传文件->End 核心代码: 连接参 ...

  5. linux-2.6.18源码分析笔记---信号

    一.相关数据结构及其位置(大致浏览即可,介绍流程时再来仔细看) 1.1 进程描述符struct task_struct所在目录:include\linux\sched.h 关注task_struct中 ...

  6. 用C#开发的一个通用的地铁换乘查询工具

    日常生活中,上班下班坐地铁已经是常事,每当我想去某一个远一点的地方,如果有地铁首选就是地铁,因为方便嘛!每次坐地铁,我们都是凭肉眼去得出我们心中最佳的换乘方案,但是,如果对于线路较少的城市来说,这个方 ...

  7. 【Python】 html解析BeautifulSoup

    BeautifulSoup bs是个html解析模块,常用来做爬虫? ■ 安装 BeautifulSoup可以通过pip来安装,用pip install beautifulsoup4 即可.但是仅仅这 ...

  8. 设计模式之 外观模式详解(Service第三者插足,让action与dao分手)

    作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. 各位好,LZ今天给各位分享一 ...

  9. Java虚拟机16:Metaspace

    被废弃的持久代 想起之前面试的时候有面试官问起过我一个问题:Java 8为什么要废弃持久代即Metaspace的作用.由于当时使用的Java 7且研究重心不在JVM上,一下没有回答上来,今天突然想起这 ...

  10. C# 7.0 观察者模式 以及 delegate 和 event

    观察者模式 这里面综合了几本书的资料. 需求 有这么个项目: 需求是这样的: 一个气象站, 有三个传感器(温度, 湿度, 气压), 有一个WeatherData对象, 它能从气象站获得这三个数据. 还 ...