前言
上一节我们讲解了线程的调度,并且也写了一个登陆功能的示例代码,只是单独的写了一个登陆的,如果是新用户,需要先注册然后登陆,这个就属于嵌套的网络请求,在这一节的最后我会给大家写两种具体的实现方式。
这一节主要内容就是介绍下操作符Map和FlatMap的用法。
1. Map操作符
作用是把上游发送的每一个事件,都按照指定的方法去变化即可。如下图所示:
由上图可知:
map中的方法的作用就是 把 圆形事件 转为 矩形事件,也就是说下游接收到的事件就是 矩形事件,示例代码如下:
/**
* map中的方法作用:
* 把圆形事件转为 矩形事件,也就是说下游接收的事件变为 矩形事件
*/
public static void demo1(){
Observable.create(new ObservableOnSubscribe() {
@Override
public void subscribe(ObservableEmitter emitter) throws Exception {
emitter.onNext(1);
emitter.onNext(2);
emitter.onNext(3);
}
}).map(new Function() {
@Override
public String apply(Integer integer) throws Exception {
return "This is result " + integer;
}
}).subscribe(new Consumer() {
@Override
public void accept(String s) throws Exception {
Log.e("TAG" , "s -> " + s) ;
}
});
}
运行结果如下:
TAG: s -> This is result 1
TAG: s -> This is result 2
TAG: s -> This is result 3
结论
通过Map,可以把上游的事件转换为任意类型,可以是一个 Object,或者是一个集合。
2. FlatMap
FlatMap作用就是 把发送事件上游的 Observable 转换为 多个发送事件的 Observables,然后把他们发射的事件合并后放到一个单独的 Observable里。
这句话可以用如下图进行理解:
由上图可知,上游发射3个事件,分别是1、2、3,注意3个颜色。
flatMap作用是把上游的3个圆形事件分别转换为一个 发射矩形事件和 一个 发射三角形事件新的上游 Observable,如果不是很理解,看下我下边的分解图解:
由分解图片可知:
1>:上游每发射一个事件,flatMap都会创建一个新的水管,也就是说上游会创建3个水管;
2>:然后把3个水管的圆形事件 全部转换为 对应的三角事件和矩形事件,然后发射转换之后新的事件;
3>:下游接收到的就是这些新的水管发射过来的数据;
注意:
1>:flatMap不能保证事件的顺序,也就是说事件1、事件2、事件3顺序不一样;
2>:如果想要保证顺序,可以使用 concatMap;
flatMap示例代码如下:
/**
* flatMap中方法作用:
* 将一个发射事件上游的Observable转换为多个发射事件的 Observable,
* 然后把转换之后的多个事件合并后放到一个单独的 Observable里
*/
public static void flatMap(){
// 创建一个上游:Observable
Observable.create(new ObservableOnSubscribe() {
@Override
public void subscribe(ObservableEmitter emitter) throws Exception {
emitter.onNext(1);
emitter.onNext(2);
emitter.onNext(3);
}
/**
* flatMap中把上游发射来的3个事件,转换为一个新的发射3个String事件的水管,
* 为了看到flatMap是无效的,下边延迟10ms
*/
}).flatMap(new Function>() {
@Override
public ObservableSource apply(Integer integer) throws Exception {
final List list = new ArrayList() ;
for (int i = 0 ; i < 3 ; i++){
list.add("I am value " + integer) ;
}
return Observable.fromIterable(list).delay(10 , TimeUnit.MILLISECONDS);
}
// 建立连接、创建一个下游:Observer
}).subscribe(new Consumer() {
@Override
public void accept(String s) throws Exception {
Log.e("TAG", "s -> " + s);
}
});
}
运行结果如下:
TAG: s -> I am value 1
TAG: s -> I am value 1
TAG: s -> I am value 1
TAG: s -> I am value 2
TAG: s -> I am value 2
TAG: s -> I am value 2
TAG: s -> I am value 3
TAG: s -> I am value 3
TAG: s -> I am value 3
concatMap与flatMap代码一样一样的,只是把 flatMap换为 concatMap即可,这样打印出来是保证顺序的。
3. 实践
针对于注册成功后然后登陆,有两种实现方式:
第一种:最常规的写法,也是最容易理解的,就是写两个方法,分别是注册和登陆即可;
/**
* 登录
*/
public static void login(final Context context){
Api api = RetrofitProvider.get().create(Api.class) ;
api.login(new LoginRequest())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(LoginResponse value) {
}
@Override
public void onError(Throwable e) {
Log.e("TAG" , "登录失败") ;
}
@Override
public void onComplete() {
Log.e("TAG" , "登录成功") ;
}
});
}
/**
* 注册
*/
public static void register(final Context context){
Api api = RetrofitProvider.get().create(Api.class) ;
api.register(new RegisterRequest())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(RegisterResponse value) {
}
@Override
public void onError(Throwable e) {
Log.e("TAG" , "注册失败") ;
}
@Override
public void onComplete() {
Log.e("TAG" , "注册成功") ;
}
});
}
第二种:使用flatMap
/**
* 使用flatMap实现嵌套的联网请求:
* 先注册、后登录
*/
public static void flatMapPritice(final Context context){
final Api api = RetrofitProvider.get().create(Api.class) ;
api.register(new RegisterRequest()) // 发起注册的请求
.subscribeOn(Schedulers.io()) // 在io线程中进行联网请求
.observeOn(AndroidSchedulers.mainThread()) // 切换到主线程中处理 注册返回的结果
.doOnNext(new Consumer() {
@Override
public void accept(RegisterResponse registerResponse) throws Exception {
// 根据请求注册接口的返回结果,然后做一些处理
}
})
.subscribeOn(Schedulers.io()) // 切换线程到主线程中 发起登录请求
.flatMap(new Function>() {
@Override
public ObservableSource apply(RegisterResponse registerResponse) throws Exception {
return api.login(new LoginRequest());
}
})
.observeOn(AndroidSchedulers.mainThread()) // 切换线程到主线程 处理登录返回的结果
.subscribe(new Observer() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(LoginResponse value) {
}
@Override
public void onError(Throwable e) {
Log.e("TAG" , "登录失败") ;
}
@Override
public void onComplete() {
Log.e("TAG" , "登录成功") ;
}
});
}
以上就是 flatMap的用法,注释写的比较清晰。
可以看出,切换线程相对来说还是比较简单的。