前言:
本文将在Rx官方解释的基础上,再融合其它国内讲解的文章。尽量用最简单的,易懂的方式,解释map()操作符。解释的过程,以问答的形式,先从整体简单解释入手,并配上能跑的示例代码(0 warnings, 0 errors)。先知道能做什么和怎么做,再讲原理,并尽量做到中英融合解释。(建议用PC端阅读,图片可以放大。排版,也有利于阅读)
一、需要了解的知识点:
Observer与Consumer的区别:后者是简化了前者,减去了许多回调接口。注意,重要的事说三遍:他们都是充当观察者角色,他们都是充当观察者角色,他们都是充当观察者角色。其它详情,可以参考这篇:Observer与Consumer的区别。
二、Map的操作流程图解
上面的线,表示原始数据。下面的线,表示转换后的数据。中间的块,代表转换过程。两条线的结尾有一小条竖线,表示结束。箭头的方向,从左到右,表示运行过程,是从左到右跑的。
三、学习之前,先来看看,一些常见的问题及解答,基于问题来学习Map操作符。
1、map()操作符能做什么?
答:map()操作符用于转换一组数据。至于怎么转换,由你自己指定。比如,简单的对数据进行加减乘除处理。又比如,将某一个类转成另一个类。又比如,将一组User类对象(userName是User类的一个字段),转成一组userName对象。
2、那它是什么时候开始转换,或者说,是如何触发转换事件的?然后,又是在哪里转换的?最后,它又是如何转换的?
答:问的有点多。。一个一个来。
- map()是什么时候开始转换的?(即如何触发转换事件),一旦,可(被)观察者(Observable),被观察者(Observer或者Consumer)订阅了,就开始进行转换。那问题来了,怎么订阅?通过设置监听回调,来建立订阅关系。
- 那在哪里进行转换处理呢?,在这个R apply(@NonNull T t) 方法里进行处理。R 和 T 都是泛型。
- 那它又是如何实现转换的?,从上一条可以看出,R apply(@NonNull T t) 方法,有两个泛型。传入apply方法的T是原数据类型,由apply方法返回的R类型,即是转换后的类型。具体的转换逻辑,在apply()方法里面,由你自己实现。
3、说了这么多,示例代码呢?要复制粘贴就能跑的那种(0 warnings,0 errors)。
答:好,但你得先配置RxJava2库。同时,在看之前,给你点提示,助你阅读。因为RxJava2是基于观察者模式,以响应流的方式对数据进行异步请求处理。所以,你在阅读代码时,只要遵循简单的从上到下的思考逻辑即可。
public static void actionMap() {
List<Integer> list = Arrays.asList(1,2,3);
Observable.fromIterable(list)
.map(new Function<Integer, String>() {
@Override
public String apply(Integer integer) throws Exception {
// Converts integer into string.
return String.valueOf(integer);
}
}).subscribe(new Consumer<String>() {
@Override
public void accept(String s) throws Exception {
// prints the converted value
log("accept=" + s );
}
});
}
我们先从上到下来分析这段代码。
首先,Observable(被观察者),通过调用fromIterable来接收一个list,做为数据源(原始数据,被转换的数据)。fromIterable在接收到数据源后,会返回调用它的Observable对象。
接着,Observable会调用map()操作符。注意啦!整容部分要开始啦。 map()操作符,接收一个函数式接口Function< T , R>。这个接口带有两个泛型参数,T是要被整容的数据的类型,R则是被整容后的结果数据的类型。然后,只要订阅关系被建立,map()操作符就会通过调用Function接口里面唯一的方法 R apply(@NonNull T t)。这个方法的作用,就像手术室的作用。T是被整容前的数据。R则是整容后的数据。T–> 整容手术室apply()–> R,就是这样一个过程。那么,这个整容后的数据,交给谁呢?在return R后,R就被Observable给接收了,同时map()方法本身,也会返回一个Observable对象。。。注意,apply()返回的是R,map()返回的才是Observable。
最后,要做的就是建立订阅关系。因为map()返回了一个Observable,所以,就可以再通过Observable,来调用一个subscribe方法,建立订阅关系。subscribe方法接收一个接口做为参数(Observer or Consumer)。代码片段中,以一个Consumer为demo。可以看到Consumer接口里面有一个void accept(T t) 方法。这个方法里面有一个T类型,这个T类型,即是被整容后的数据的类型。变量t,则是被整容后的数据。剩下的,你想要对这个被整容后,变漂亮的t做什么下流的事,我就不管了。
上面部分是以Consumer为例,再举一个以Observer为例的,同样地,让我们来看代码:
Observable.fromIterable(list)
.map(new Function<Integer, String>() {
@Override
public String apply(Integer integer) throws Exception {
// Converts integer into string.
log("apply");
return String.valueOf(integer);
}
}).subscribe(new Observer<String>() {
@Override
public void onSubscribe(Disposable d) {
// d.dispose(); Cancel Converts
log("onSubscribe" );
}
@Override
public void onNext(String s) {
// get 's' from apply().
log("onNext=" + s );
}
@Override
public void onError(Throwable e) {
// invoked when an exception occurred.
// if onError be invoked, The onComplete will never be invoked.
// it means the Observer will invoke either the onError or the onComplete.
log("onError");
}
@Override
public void onComplete() {
// invoked when transforming job done.
log("onComplete");
}
});
这是输出的信息:
D/TransformingOperations: onSubscribe
D/TransformingOperations: apply
D/TransformingOperations: onNext=1
D/TransformingOperations: apply
D/TransformingOperations: onNext=2
D/TransformingOperations: apply
D/TransformingOperations: onNext=3
D/TransformingOperations: onComplete
前面部分代码,跟Consumer的没区别。重点看Observer回调部分。可以这样理解,apply()方法每执行一次,onNext就会被执行一次。直到所有数据都被转换成功后,onComplete方法就会被调用。如果,在这个转换的过程中,发生什么异常。那么,就不会执行onComplete,而是执行onError方法。然后,onSubscribe最先被调用,所以,可以在这里做一些准备工作。至于线程切换调度的,不属于操作符的讲解范畴,这里就不做示例解释了。
本篇到此结束,如果觉得,问答过程或是分析过程,有什么不易理解,或不到位的。可以在评论区,指出。欢迎批评指正。
附上可以跑的代码(0 warnings, 0 errors):
https://github.com/SuperBeagleDog/OkMVP
注意:
这个库里面有很多东西,RxJava2的转换操作符部分的demo位于:com.lyf.okmvp.demo.rxjava2包下的TransformingOperations类里面。
用法:
1、直接在com.lyf.okmvp.ui包下的MainActivity类里的onCreate()方法里面,直接调用:
TransformingOperations.actionMap(); // 静态方法。
2、也可以复制TransformingOperations类到你的项目里,去为所欲为。但前提时,你得有配置过RxJava和RxAndroid。配置方法,自行百度,或参考我的OkMVP库。