前面两篇文章中我们介绍了RxJava的一些基本概念和RxJava最简单的用法。从这一篇开始,我们开始聊聊RxJava中的操作符Operators。
RxJava中的操作符主要分成了三类:
- 转换类操作符(map flatMap concatMap flatMapIterable switchMap scan groupBy ...);
- 过滤类操作符(fileter take takeLast takeUntil distinct distinctUntilChanged skip skipLast ...);
- 组合类操作符(merge zip join combineLatest and/when/then switch startSwitch ...)。
这一篇主要介绍几个常用的转换操作符——map、flatMap和groupBy。
所有这些Operators都作用于一个可观测序列,然后变换它发射的值,最后用一种新的形式返回它们。概念实在是不好理解,下面我们结合实际的例子一一介绍。
map
map操作符,就是用来把把一个事件转换为另一个事件的。map()操作符就是用于变换Observable对象的,map操作符返回一个Observable对象,这样就可以实现链式调用,在一个Observable对象上多次使用map操作符,最终将最简洁的数据传递给Subscriber对象。
看个例子:
Observable.from(list)
.map(new Func1<Person, Person>() {
@Override
public Person call(Person person) {
if (person.getAge() % 2 == 0)
person.setName("js");
return person;
}
})
.subscribe(new Action1<Person>() {
@Override
public void call(Person person) {
Log.e("map", "call: " + person.toString());
}
});
上面的例子,发射源发射一个Person数据集合,然后执行map操作,将数据集合中的数据,判断如果年龄是偶数,就将其名字改为“js”,然后返回,最终观察者中打印。
这个例子只是简单的解释map操作符的作用,其核心就是将数据进行转换,数据转换在map操作符的Func1中实现,Func1第一个泛型是传入类型,第二个泛型是输出类型,在call方法中实现转换,当然传入类型和输出类型完全可以不同。
再看个例子:
Observable.just("images/logo.png") // 输入类型 String
.map(new Func1<String, Bitmap>() {
@Override
public Bitmap call(String filePath) { // 参数类型 String
return getBitmapFromPath(filePath); // 返回类型 Bitmap
}
})
.subscribe(new Action1<Bitmap>() {
@Override
public void call(Bitmap bitmap) { // 参数类型 Bitmap
showBitmap(bitmap);
}
});
这个例子就更贴合实际开发了,发射器发射一个图片地址,在map操作符中根据图片地址加载返回Bitmap对象交给接收器,在接收器中接受Bitmap进行展示。
当然,进行图片加载和图片展示应该分别位于子线程和主线程中执行,这里就用到了RxJava的线程调度器,这个之后再介绍。这里只是展示map操作符的用法和作用。
可以看出:
map() 方法将参数中的 String 对象转换成一个 Bitmap 对象后返回,而在经过 map() 方法后,事件的参数类型也由 String 转为了 Bitmap。这种直接变换对象并返回的,是最常见的也最容易理解的变换。不过 RxJava 的变换远不止这样,它不仅可以针对事件对象,还可以针对整个事件队列,这使得 RxJava 变得非常灵活。
flatMap
map适用于一对一转换,当然也可以配合flatmap进行适用,flatmap适用于一对多,多对多的场景。
先从一个例子入手:
List<Student> students = new ArrayList<>();
for (int i = 0; i < 3; i++) {
Student student = new Student();
List<Student.Course> courses = new ArrayList<>();
for (int j = 0; j < 6; j++) {
Student.Course course = new Student.Course("课程" + j);
courses.add(course);
}
student.setList(courses);
students.add(student);
}
Observable.from(students)
.flatMap(new Func1<Student, Observable<Student.Course>>() {
@Override
public Observable<Student.Course> call(Student student) {
return Observable.from(student.getList());
}
})
.subscribe(new Action1<Student.Course>() {
@Override
public void call(Student.Course r) {
Log.e("flatMap", "call: " + r.toString());
}
});
现在有一个学生集合,每个学生又都有一个课程集合,业务要求将每个学生所选的每个课程全部打印,我们就可以使用flatMap操作符。
原始发射源发射学生集合,在flatMap操作符中获取学生对应的课程集合,再将其转换为一个新的Observable对象返回,最终接收器中打印课程。根据输出结果可以发现,转换后的发射源发射集合,接收器中逐个打印,接下来原始反射器发射第二个学生对象,再执行flatMap转换为新的Observable对象,再逐个打印该学生的所有课程对象。。。
map与flatMap的区别:
- map返回的是结果集,flatmap返回的是包含结果集的Observable(返回结果不同)。
- map被订阅时每传递一个事件执行一次onNext方法, flatmap多用于多对多,一对多,再被转化为多个时,一般利用from/just进行一一分发。被订阅时将所有数据传递完毕汇总到一个Observable然后一一执行onNext方法(执行顺序不同)。
- map只能单一转换,单一指的是只能一对一进行转换,指一个对象可以转化为另一个对象但是不能转换成对象数组;map返回结果集不能直接使用from/just再次进行事件分发,一旦转换成对象数组的话,再处理集合/数组的结果时需要利用for一一遍历取出,而使用RxJava就是为了剔除这样的嵌套结构,使得整体的逻辑性更强。)flatmap既可以单一转换也可以一对多/多对多转换,flatmap要求返回Observable,因此可以再内部进行from/just的再次事件分发,一一取出单一对象(转换对象的能力不同)。
groupBy
groupBy顾名思义就是分组的意思。
将一个Observable分拆为一些Observables集合,它们中的每一个发射原始Observable的一个子序列,GroupBy操作符将原始Observable分拆为一些Observables集合,它们中的每一个发射原始Observable数据序列的一个子序列。哪个数据项由哪一个Observable发射是由一个函数判定的,这个函数给每一项指定一个Key,Key相同的数据会被同一个Observable发射。
Observable from = Observable.from(list);
from.groupBy(new Func1<Object,Integer>() {
@Override
public Integer call(Object o) {
String name = o.getClass().getName();
String a = A.class.getName();
String b = B.class.getName();
String c = C.class.getName();
if (name.equals(a)){
return 1;
}else if(name.equals(b)){
return 2;
}else if(name.equals(c)){
return 3;
}
return 4;
}
})
.subscribe(new Action1<GroupedObservable<Integer,Object>>() {
@Override
public void call(GroupedObservable<Integer,Object> objectIntegerGroupedObservable) {
int sign = objectIntegerGroupedObservable.getKey();
switch (sign){
case 1:
objectIntegerGroupedObservable.subscribe(new Action1<Object>() {
@Override
public void call(Object a) {
Log.d("groupby","class A - "+a.getClass().getName());
}
});
break;
case 2:
objectIntegerGroupedObservable.subscribe(new Action1<Object>() {
@Override
public void call(Object a) {
Log.d("groupby","class B - "+a.getClass().getName());
}
});
break;
case 3:
objectIntegerGroupedObservable.subscribe(new Action1<Object>() {
@Override
public void call(Object a) {
Log.d("groupby","class C - "+a.getClass().getName());
}
});
break;
default:
Log.d("groupby","other class");
break;
}
}
});
实践出真知 先构造了三个类A,B,C,用一个List装了他们的若干个实例,随机的,再使用Observer发射出去,经过GroupBy的作用后打印结果。
在GroupBy的Func1()函数中按你的逻辑分组,并将每个信息对应的组的key标志返回,如例子中我个标志都是Integer类型的,GroupBy会返回Observable的一个特殊子类GroupedObservable,这个特殊子类有个额外的方法getKey(),可用于获得当前信息的组别。
ok,RxJava的转换操作符就下你介绍到这里,更多精彩内容,欢迎关注我的微信公众号——Android机动车