RxJava从入门到不离不弃(三)——转换操作符

725 阅读6分钟

前面两篇文章中我们介绍了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、flatMapgroupBy

所有这些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的区别:

  1. map返回的是结果集,flatmap返回的是包含结果集的Observable(返回结果不同)。
  2. map被订阅时每传递一个事件执行一次onNext方法, flatmap多用于多对多,一对多,再被转化为多个时,一般利用from/just进行一一分发。被订阅时将所有数据传递完毕汇总到一个Observable然后一一执行onNext方法(执行顺序不同)。
  3. 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机动车

这里写图片描述