上一篇學完了Observable和Observer,這一篇學一下map操作符和flatMap操作符
1.先看一下map操作符:
map是RxJava中最簡單的一個變換操作符了,map操作符的作用是將上游(Observable)發送的每一個事件,轉換成一個函數,使得每一個上游發送的事件都按照指定的規則去做。
下面先看一個例子:
Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(ObservableEmitter<Integer> e) throws Exception {
Log.d("----", "subscribe: 發送的信息:"+1);
e.onNext(1);
Log.d("----", "subscribe: 發送的信息:"+2);
e.onNext(2);
Log.d("----", "subscribe: 發送的信息:"+3);
e.onNext(3);
Log.d("----", "subscribe: 完成");
e.onComplete();
}
}).map(new Function<Integer, String>() {
@Override
public String apply(Integer integer) throws Exception {
//map的作用就是轉化,這裏將int類型的數據 轉換爲 String類型的數據
return "this is " + integer;
}
}).subscribe(new Consumer<String>() {
@Override
public void accept(String s) throws Exception {
Log.d("----", "accept: 接收到的信息:"+s);
}
});
在上游我們發送的是數字類型, 而在下游我們接收的是String類型, 中間起轉換作用的就是map操作符
看一下Log輸出:
02-05 16:19:06.549 14418-14418/com.ckw.rxjava2demo D/----: subscribe: 發送的信息:1
02-05 16:19:06.549 14418-14418/com.ckw.rxjava2demo D/----: accept: 接收到的信息:this is 1
02-05 16:19:06.549 14418-14418/com.ckw.rxjava2demo D/----: subscribe: 發送的信息:2
02-05 16:19:06.549 14418-14418/com.ckw.rxjava2demo D/----: accept: 接收到的信息:this is 2
02-05 16:19:06.550 14418-14418/com.ckw.rxjava2demo D/----: subscribe: 發送的信息:3
02-05 16:19:06.550 14418-14418/com.ckw.rxjava2demo D/----: accept: 接收到的信息:this is 3
02-05 16:19:06.550 14418-14418/com.ckw.rxjava2demo D/----: subscribe: 完成
從log信息中我們可以看到,上游發送的是Int類型的數據,通過map操作符,轉成了String。
接着看flatMap:
FlatMap將一個發送事件的上游Observable變換爲多個發送事件的Observables,然後將它們發射的事件合併後放進一個單獨的Observable裏.
上游每發送一個事件, flatMap都將創建一個新的水管, 然後發送轉換之後的新的事件,
下游接收到的就是這些新的水管發送的數據. 這裏需要注意的是, flatMap並不保證事件的順序
看一下例子:
Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(ObservableEmitter<Integer> e) throws Exception {
Log.d("----", "subscribe: 上游發送:1");
e.onNext(1);
Log.d("----", "subscribe: 上游發送:2");
e.onNext(2);
Log.d("----", "subscribe: 上游發送:3");
e.onNext(3);
Log.d("----", "subscribe: 上游發送完畢");
e.onComplete();
}
}).flatMap(new Function<Integer, ObservableSource<String>>() {
@Override
public ObservableSource<String> apply(Integer integer) throws Exception {
List<String> list = new ArrayList<>();
for (int i = 0; i < 3; i++) {
list.add("this is "+integer);
}
return Observable.fromIterable(list).delay(10,TimeUnit.MILLISECONDS);
}
}).subscribe(new Consumer<String>() {
@Override
public void accept(String s) throws Exception {
Log.d("----", "accept: 接收到的信息:"+s);
}
});
Observable.fromIterable:
此方法接收一個繼承自Iterable接口的參數,簡單的說就是java中的集合類。因此你可以傳入一個list集合等等
看一下Log輸出:
02-05 16:23:29.263 15724-15724/com.ckw.rxjava2demo D/----: subscribe: 上游發送:1
02-05 16:23:29.281 15724-15724/com.ckw.rxjava2demo D/----: subscribe: 上游發送:2
02-05 16:23:29.282 15724-15724/com.ckw.rxjava2demo D/----: subscribe: 上游發送:3
02-05 16:23:29.283 15724-15724/com.ckw.rxjava2demo D/----: subscribe: 上游發送完畢
02-05 16:23:29.291 15724-15772/com.ckw.rxjava2demo D/----: accept: 接收到的信息:this is 1
02-05 16:23:29.292 15724-15773/com.ckw.rxjava2demo D/----: accept: 接收到的信息:this is 2
02-05 16:23:29.292 15724-15774/com.ckw.rxjava2demo D/----: accept: 接收到的信息:this is 3
3.模擬註冊登錄:
使用FlatMap模擬用戶先註冊,註冊成功後直接登錄的功能:
final Api api = create().create(Api.class);
// //之前有說過,只能subscribeOn一次,可以observeOn多次
api.register("ckw")//發起註冊請求
.subscribeOn(Schedulers.io())//在io線程發起網絡請求
.observeOn(AndroidSchedulers.mainThread())//在主線程處理註冊請求結果
.doOnNext(new Consumer<String>() {//感覺不是必須的,如果不用處理註冊結果,就不需要了吧
@Override
public void accept(String s) throws Exception {
//先對註冊的結果進行一些處理,這步不是必須的
}
})
.observeOn(Schedulers.io())//在io線程處理登錄請求
.flatMap(new Function<String, ObservableSource<String>>() {
@Override
public ObservableSource<String> apply(String s) throws Exception {
//發起登錄的網絡請求
return api.login("ckw");
}
})
.observeOn(AndroidSchedulers.mainThread())//在主線程處理登錄請求結果
.subscribe(new Consumer<String>() {
@Override
public void accept(String s) throws Exception {
Log.d("----", "accept: 登錄成功");
}
}, new Consumer<Throwable>() {
@Override
public void accept(Throwable throwable) throws Exception {
Log.d("----", "accept: 登錄失敗");
}
});
在這裏我的返回值都是String,只是一個模擬的效果,實際上還是要根據自己的需求,創建數據類。
這是模擬的返回Retrofit的方法
private static Retrofit create() {
OkHttpClient.Builder builder = new OkHttpClient().newBuilder();
builder.readTimeout(10, TimeUnit.SECONDS);
builder.connectTimeout(9, TimeUnit.SECONDS);
if (BuildConfig.DEBUG) {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
builder.addInterceptor(interceptor);
}
return new Retrofit.Builder().baseUrl( "http://10.71.33.67:80")
.client(builder.build())
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
}