flatMap,concatMap
flatMap操作符可以将一个Observable转换为另一个Observable发射出去,并且可以将多个事件转化为1个,但是最后输出的事件序列顺序是不确定的,如果想要最后输出的事件顺序和源数据的顺序一致只要换成concatMap就可以了。
flatMap和Map操作符的不同是map一次只能转换一个事件。
代码地址:
GodisGod/Rxjava2Test
https://github.com/GodisGod/Rxjava2Test
代码实战:
根据学生的成绩输出对老师的描述
Observable.create(new ObservableOnSubscribe<Student>() {
@Override
public void subscribe(ObservableEmitter<Student> e) throws Exception {
List<Student> students = new ArrayList<Student>();
students.add(new Student("LHD1", 60));
students.add(new Student("LHD2", 70));
for (Student s : students) {
e.onNext(s);//发送多个事件
}
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.flatMap(new Function<Student, ObservableSource<Integer>>() {
@Override
public ObservableSource<Integer> apply(Student student) throws Exception {
List<Integer> lists = new ArrayList<>();
lists.add(student.getMath());
lists.add(student.getEnglish());
lists.add(student.getChinese());//将每个事件又分成多个事件
return Observable.fromIterable(lists).delay(10, TimeUnit.NANOSECONDS);//将这些事件合并成一个Observable
}
})
.subscribe(new Consumer<Integer>() {
@Override
public void accept(Integer integers) throws Exception {
Log.i("LHD", "成绩: " + integers.toString());
}
});
上面的代码中一共发出了5个学生事件,然后我们将每一个学生的成绩又分成三个事件,最后将成绩合并为一个Observable将成绩列表发射出去。
结果:
每点击一次按钮就会发送两个学生的成绩,前两次点击都会按照顺序发送,第三次点击的时候,发现两个人的成绩事件交叉在了一起,而不是先发完送一个人的再发送另一个人的,这说明flatmap的事件发送是无序的。
具体请看源码哦(#^.^#)
附上一张flatmap的流程图:
其中圆形可以看成每一个学生事件,三角形和正方形则可以看成是每个学生的成绩事件。最后的事件流向,可以发现两个学生的成绩是无序的。
flatMap可以连续多次调用
代码示例:
Observable.create(new ObservableOnSubscribe<List<Student>>() {
@Override
public void subscribe(ObservableEmitter<List<Student>> e) throws Exception {
List<Student> students = new ArrayList<Student>();
students.add(new Student("LHD1", 60));
students.add(new Student("LHD2", 70));
students.add(new Student("LHD3", 80));
students.add(new Student("LHD4", 90));
students.add(new Student("LHD5", 100));
e.onNext(students);
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.flatMap(new Function<List<Student>, ObservableSource<Teacher>>() {
@Override
public ObservableSource<Teacher> apply(List<Student> students) throws Exception {
Teacher teacher = new Teacher();
teacher.setName("笨老师");
teacher.setGood(false);
for (Student s : students) {
if (s.getScore() > 90) {
teacher.setName("好老师");
teacher.setGood(true);
}
}
return Observable.just(teacher);
}
})
.flatMap(new Function<Teacher, ObservableSource<String>>() {
@Override
public ObservableSource<String> apply(Teacher teacher) throws Exception {
String str = "这个 " + teacher.getName() + " good 不?";
return Observable.just(str);
}
})
.subscribe(new Consumer<String>() {
@Override
public void accept(String string) throws Exception {
Log.i("LHD", string);
tvResult.setText(string);
}
});
上面的代码我们使用了两次flatMap,第一次将5个学生事件转变为1个老师事件,第二次将老师事件转化为一个字符串,最后将这个字符串发射出去。
flatMap转换后的数据是无序的
代码示例:
Observable.create(new ObservableOnSubscribe<Student>() {
@Override
public void subscribe(ObservableEmitter<Student> e) throws Exception {
e.onNext(new Student("第一名", 100));
e.onNext(new Student("第二名", 90));
e.onNext(new Student("第三名", 80));
}
}).subscribeOn(Schedulers.io())
.flatMap(new Function<Student, ObservableSource<String>>() {
@Override
public ObservableSource<String> apply(Student student) throws Exception {
final String str = "老师正在教导" + student.getName() + ",她考了" + student.getScore() + "分";
Log.i("LHD1", str);//在这里检测事件的转换顺序
int delay = 100;
if (student.getScore() == 100) {
delay = 500;
}
return Observable.just(str).delay(delay, TimeUnit.MILLISECONDS);
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<String>() {
@Override
public void accept(String s) throws Exception {
tvResult.append(s + "\n");
Log.i("LHD2", s + "\n");//在这里检测事件的接受顺序
}
});
为了能观察到事件是无序的,我们把第一个事件的学生成绩设置为100,然后在flatMap里判断当学生的成绩为100的时候我们延时500ms再发射事件。
结果:
可以发现我们转换事件的顺序是和数据源相同的但是发射事件的顺序果然变得无序了。
本来应该是100,90,80结果在接收端变成了90,80,100
可以发现事件顺序是:
LHD1—100 发射端
LHD1—90 发射端
LHD2—100
LHD1—80 发射端
LHD2—90
LHD2—80
可以看到使用concatMap转换后的事件仍然是有序的
以上就是flatMap和concatMap的简单介绍啦。