前言
我们在开发的过程中经常碰到对象转换的问题,比如上一篇文章提到的Url对象转换为Drawable对象,有时还要转成Bitmap对象。
这都还是一些相对比较简单的对象转换逻辑,要是复杂的网络嵌套呢?比如新用户的注册后登录逻辑
这时候,强大的RxJava又出来了(你怎么什么都会!!)
所以,我们今天就来介绍一下RxJava的转换操作符吧。
map
map是RxJava中最简单的一个变换操作符了, 它的作用就是对上游发送的每一个事件经过map去调用一个方法进行处理, 使得每一个事件都按照指定的方法发生变换。
如图所示(一个圆形事件经过map()变成方形事件):
相信大家应该都能理解上面这幅图吧,接下来我们上个“栗子”
Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(ObservableEmitter<Integer> e) throws Exception {
e.onNext(1);
e.onNext(2);
}
}).map(new Function<Integer, String>() {
@Override
public String apply(Integer integer) throws Exception {
return "After map: " + integer;
}
}).subscribe(new Consumer<String>() {
@Override
public void accept(String s) throws Exception {
Log.d(TAG, s);
}
});
输出结果:我们在上游发送出的Integer类型的对象已经变成了String类型,中间起作用的就是map操作符啦。
flatMap
介绍完map操作符,我们再来介绍一下flatMap
先看一张图:
是不是看不懂?看不懂就对了!
flatMap的确是个很难理解的操作符,我们来拆解一下flatMap到底做了什么
flatMap将圆形事件转换成一个发送矩形事件和三角形事件的新的上游Observable,将新的Observable发送出去
(Tip:flatMap并不保证发送时间见的顺序,所以才会出现下游乱序的情况 )
我们来看一下flatMap的例子
Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(ObservableEmitter<Integer> e) throws Exception {
e.onNext(1);
e.onNext(2);
e.onNext(3);
}
}).flatMap(new Function<Integer, ObservableSource<String>>() {
@Override
public ObservableSource<String> apply(Integer integer) throws Exception {
final List<String> list = new ArrayList<>();
for (int i = 0; i < 3; i++) {
list.add("The value is " + integer);
}
return Observable.fromIterable(list).delay(100, TimeUnit.MILLISECONDS);
}
}).subscribe(new Consumer<String>() {
@Override
public void accept(String s) throws Exception {
Log.d(TAG, s);
}
});
输出结果:我们在flatMap中将上游发来的每个Integer类型的事件转换为一个新的发送三个String类型的事件, 为了看到flatMap结果是无序的,所以加了100毫秒的延时。
concatMap
concatMap和flatMap的作用几乎一样, 只是它的结果是严格按照上游发送的顺序来发送的,所以是有序的。
修改上面flatMap的代码
Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(ObservableEmitter<Integer> e) throws Exception {
e.onNext(1);
e.onNext(2);
e.onNext(3);
}
}).concatMap(new Function<Integer, ObservableSource<String>>() {
@Override
public ObservableSource<String> apply(Integer integer) throws Exception {
final List<String> list = new ArrayList<>();
for (int i = 0; i < 3; i++) {
list.add("The value is " + integer);
}
return Observable.fromIterable(list).delay(100, TimeUnit.MILLISECONDS);
}
}).subscribe(new Consumer<String>() {
@Override
public void accept(String s) throws Exception {
Log.d(TAG, s);
}
});
输出结果:
map和flatMap的共同点和区别
共同点:
都是依赖Function(入参,返回值)进行转换
都能在转换后直接被subscribe
区别:
map只能单一转换,单一只的是只能一对一进行转换,指一个对象可以转化为另一个对象但是不能转换成对象数组(map返回结果集不能直接使用from/just再次进行事件分发,一旦转换成对象数组的话,再处理集合/数组的结果时需要利用for一一遍历取出,而使用RxJava就是为了剔除这样的嵌套结构,使得整体的逻辑性更强。)
flatmap既可以单一转换也可以一对多/多对多转换,flatmap要求返回Observable,因此可以再内部进行from/just的再次事件分发,一一取出单一对象(转换对象的能力不同)
实战
看完map和flatMap的区别,我们来实战演练一下,使用的例子为打印学生的课程名
map实现:
Observable.fromIterable(students)
.map(new Function<String, List<Course>>() {
@Override
public List<Course> apply(String students) throws Exception {
return getCoursesList(students);
}
}).subscribe(new Consumer<List<Course>>() {
@Override
public void accept(List<Course> courses) throws Exception {
for (int i = 0; i <courses.size(); i++) {
Log.d(TAG, courses.get(i).getName());
}
}
});
flatMap实现:
Observable.fromIterable(students)
.flatMap(new Function<String, ObservableSource<Course>>() {
@Override
public ObservableSource<Course> apply(String s) throws Exception {
return Observable.fromIterable(getCoursesList(students));
}
}).subscribe(new Consumer<Course>() {
@Override
public void accept(Course course) throws Exception {
Log.d(TAG, course.getName());
}
});