RxJava提供了幾個(gè)mapping函數(shù):map(),flatMap(),concatMap(),flatMapIterable()以及switchMap().所有這些函數(shù)都作用于一個(gè)可觀測(cè)序列,然后變換它發(fā)射的值,最后用一種新的形式返回它們。讓我們用合適的“真實(shí)世界”的例子一個(gè)個(gè)的學(xué)習(xí)下。
RxJava的map函數(shù)接收一個(gè)指定的Func對(duì)象然后將它應(yīng)用到每一個(gè)由Observable發(fā)射的值上。下圖展示了如何將一個(gè)乘法函數(shù)應(yīng)用到每個(gè)發(fā)出的值上以此創(chuàng)建一個(gè)新的Observable來發(fā)射轉(zhuǎn)換的數(shù)據(jù)。
http://wiki.jikexueyuan.com/project/rxjava/images/chapter5_1.png" alt="" />
考慮下我們已安裝的應(yīng)用列表。我們?cè)趺床拍軌蝻@示同樣的列表,但是又要所有的名字都小寫呢?
我們的loadList()函數(shù)可以改成這樣:
private void loadList(List<AppInfo> apps) {
mRecyclerView.setVisibility(View.VISIBLE);
Observable.from(apps)
.map(new Func1<AppInfo,AppInfo>(){
@Override
public Appinfo call(AppInfo appInfo){
String currentName = appInfo.getName();
String lowerCaseName = currentName.toLowerCase();
appInfo.setName(lowerCaseName);
return appInfo;
}
})
.subscribe(new Observer<AppInfo>() {
@Override
public void onCompleted() {
mSwipeRefreshLayout.setRefreshing(false);
}
@Override
public void onError(Throwable e) {
Toast.makeText(getActivity(), "Something went wrong!", Toast.LENGTH_SHORT).show();
mSwipeRefreshLayout.setRefreshing(false);
}
@Override
public void onNext(AppInfo appInfo) {
mAddedApps.add(appInfo);
mAdapter.addApplication(mAddedApps.size() - 1,appInfo);
}
});
}
正如你看到的,像往常一樣創(chuàng)建我們發(fā)射的Observable之后,我們追加一個(gè)map調(diào)用,我們創(chuàng)建一個(gè)簡(jiǎn)單的函數(shù)來更新AppInfo對(duì)象并提供一個(gè)名字小寫的新版本給觀察者。
在復(fù)雜的場(chǎng)景中,我們有一個(gè)這樣的Observable:它發(fā)射一個(gè)數(shù)據(jù)序列,這些數(shù)據(jù)本身也可以發(fā)射Observable。RxJava的flatMap()函數(shù)提供一種鋪平序列的方式,然后合并這些Observables發(fā)射的數(shù)據(jù),最后將合并后的結(jié)果作為最終的Observable。
http://wiki.jikexueyuan.com/project/rxjava/images/chapter5_2.png" alt="" />
當(dāng)我們?cè)谔幚砜赡苡写罅康腛bservables時(shí),重要是記住任何一個(gè)Observables發(fā)生錯(cuò)誤的情況,flatMap()將會(huì)觸發(fā)它自己的onError()函數(shù)并放棄整個(gè)鏈。
重要的一點(diǎn)提示是關(guān)于合并部分:它允許交叉。正如上圖所示,這意味著flatMap()不能夠保證在最終生成的Observable中源Observables確切的發(fā)射順序。
RxJava的concatMap()函數(shù)解決了flatMap()的交叉問題,提供了一種能夠把發(fā)射的值連續(xù)在一起的鋪平函數(shù),而不是合并它們,如下圖所示:
http://wiki.jikexueyuan.com/project/rxjava/images/chapter5_3.png" alt="" />
作為*map家族的一員,flatMapInterable()和flatMap()很像。僅有的本質(zhì)不同是它將源數(shù)據(jù)兩兩結(jié)成對(duì)并生成Iterable,而不是原始數(shù)據(jù)項(xiàng)和生成的Observables。
http://wiki.jikexueyuan.com/project/rxjava/images/chapter5_4.png" alt="" />
如下圖所示,switchMap()和flatMap()很像,除了一點(diǎn):每當(dāng)源Observable發(fā)射一個(gè)新的數(shù)據(jù)項(xiàng)(Observable)時(shí),它將取消訂閱并停止監(jiān)視之前那個(gè)數(shù)據(jù)項(xiàng)產(chǎn)生的Observable,并開始監(jiān)視當(dāng)前發(fā)射的這一個(gè)。
http://wiki.jikexueyuan.com/project/rxjava/images/chapter5_5.png" alt="" />
RxJava的scan()函數(shù)可以看做是一個(gè)累積函數(shù)。scan()函數(shù)對(duì)原始Observable發(fā)射的每一項(xiàng)數(shù)據(jù)都應(yīng)用一個(gè)函數(shù),計(jì)算出函數(shù)的結(jié)果值,并將該值填充回可觀測(cè)序列,等待和下一次發(fā)射的數(shù)據(jù)一起使用。
作為一個(gè)通用的例子,給出一個(gè)累加器:
Observable.just(1,2,3,4,5)
.scan((sum,item) -> sum + item)
.subscribe(new Subscriber<Integer>() {
@Override
public void onCompleted() {
Log.d("RXJAVA", "Sequence completed.");
}
@Override
public void onError(Throwable e) {
Log.e("RXJAVA", "Something went south!");
}
@Override
public void onNext(Integer item) {
Log.d("RXJAVA", "item is: " + item);
}
});
我們得到的結(jié)果是:
RXJAVA: item is: 1
RXJAVA: item is: 3
RXJAVA: item is: 6
RXJAVA: item is: 10
RXJAVA: item is: 15
RXJAVA: Sequence completed.
我們也可以創(chuàng)建一個(gè)新版本的loadList()函數(shù)用來比較每個(gè)安裝應(yīng)用的名字從而創(chuàng)建一個(gè)名字長(zhǎng)度遞增的列表。
private void loadList(List<AppInfo> apps) {
mRecyclerView.setVisibility(View.VISIBLE);
Observable.from(apps)
.scan((appInfo,appInfo2) -> {
if(appInfo.getName().length > appInfo2.getName().length()){
return appInfo;
} else {
return appInfo2;
}
})
.distinct()
.subscribe(new Observer<AppInfo>() {
@Override
public void onCompleted() {
mSwipeRefreshLayout.setRefreshing(false);
}
@Override
public void onError(Throwable e) {
Toast.makeText(getActivity(), "Something went wrong!", Toast.LENGTH_SHORT).show();
mSwipeRefreshLayout.setRefreshing(false);
}
@Override
public void onNext(AppInfo appInfo) {
mAddedApps.add(appInfo);
mAdapter.addApplication(mAddedApps.size() - 1,appInfo);
}
});
}
結(jié)果如下:
http://wiki.jikexueyuan.com/project/rxjava/images/chapter5_6.png" alt="" />
有一個(gè)scan()函數(shù)的變體,它用初始值作為第一個(gè)發(fā)射的值,方法簽名看起來像:scan(R,Func2),如下圖中的例子這樣:
http://wiki.jikexueyuan.com/project/rxjava/images/chapter5_7.png" alt="" />