RxJava系列文章目錄導(dǎo)讀:
一语婴、RxJava create操作符的用法和源碼分析
二、RxJava map操作符用法詳解
三驶睦、RxJava flatMap操作符用法詳解
四砰左、RxJava concatMap操作符用法詳解
五、RxJava onErrorResumeNext操作符實(shí)現(xiàn)app與服務(wù)器間token機(jī)制
六场航、RxJava retryWhen操作符實(shí)現(xiàn)錯(cuò)誤重試機(jī)制
七缠导、RxJava 使用debounce操作符優(yōu)化app搜索功能
八、RxJava concat操作處理多數(shù)據(jù)源
九溉痢、RxJava zip操作符在Android中的實(shí)際使用場(chǎng)景
十僻造、RxJava switchIfEmpty操作符實(shí)現(xiàn)Android檢查本地緩存邏輯判斷
十一憋他、RxJava defer操作符實(shí)現(xiàn)代碼支持鏈?zhǔn)秸{(diào)用
十二、combineLatest操作符的高級(jí)使用
十三髓削、RxJava導(dǎo)致Fragment Activity內(nèi)存泄漏問題
十四举瑰、interval、takeWhile操作符實(shí)現(xiàn)獲取驗(yàn)證碼功能
combineLatest 操作符用來將多個(gè)Observable發(fā)射的數(shù)據(jù)組裝起來然后在發(fā)射. 通過Func類來組裝多個(gè)Observable發(fā)射的數(shù)據(jù), 等到最后一個(gè)Observable發(fā)射數(shù)據(jù)了, 然后把所有發(fā)射的數(shù)據(jù)交給Fun進(jìn)行組合, 然后把組合后的數(shù)據(jù)發(fā)射出去.
看到網(wǎng)上絕大部分都是用 combineLatest 來做Android表單的校驗(yàn), 總感覺有點(diǎn)大材小用. 如只有表單都只有值了了, 提交按鈕才可用:
Observable<CharSequence> etFeedbackInputObservable = RxTextView.textChanges(mEditFeedbackInput).skip(1);
Observable<CharSequence> etFeedbackEmailObservable = RxTextView.textChanges(mEditFeedbackEmail).skip(1);
Observable.combineLatest(etFeedbackInputObservable, etFeedbackEmailObservable, new Func2<CharSequence, CharSequence, Boolean>() {
@Override
public Boolean call(CharSequence charSequence, CharSequence charSequence2) {
boolean inputValid = !TextUtils.isEmpty(charSequence);
boolean emailValid = !TextUtils.isEmpty(charSequence2);
return inputValid && emailValid;
}
}).subscribe(new Observer<Boolean>() {
@Override
public void onCompleted() {
Logger.d("onCompleted");
}
@Override
public void onError(Throwable e) {
Logger.e("onError-->" + e.toString());
}
@Override
public void onNext(Boolean aBoolean) {
//讓提交表單可以單擊
mButtonSendFeedback.setEnabled(aBoolean);
}
});
在實(shí)際的項(xiàng)目開發(fā)中, combineLatest操作除了可以做一些簡單的表單校驗(yàn), 還可以做更加復(fù)雜的業(yè)務(wù)場(chǎng)景, 最重要的是遇到了這種場(chǎng)景能夠用RxJava操作符來解決.
再上家公司有這樣一個(gè)業(yè)務(wù)場(chǎng)景: 一個(gè)用戶查看自己的訂單列表(該用戶是藝術(shù)家在平臺(tái)上賣藝術(shù)品的), 界面除了展示訂單的基本信息, 還需要在Item的底部展示是哪個(gè)用戶購買的(展示購買者的頭像和名字), 但是后臺(tái)返回的JSON數(shù)據(jù)對(duì)應(yīng)的Bean如下所示 :
public class JsonOrderPage<Order> {
public List<Order> data;
public Paging paging;
}
似乎感覺也沒什么, 但是后臺(tái)返回的Order對(duì)象里對(duì)于購買者的信息只有購買者的id, 但是界面上需要顯示購買者的名字和頭像. 說白了需要根據(jù)購買者的id來獲取購買者的信息. 如果后端返回的僅僅是個(gè)List就好了, 那就用flatMap操作符很好的解決了. 當(dāng)然最直觀的解決方式就是for循序環(huán), 如下所示:
Observable<JsonOrderPage> observableUser = xxx;
observableJsonOrderPage.flatMap(new Func1<JsonOrderPage, Observable<JsonOrderPage>>() {
@Override
public Observable<JsonOrderPage> call(JsonOrderPage page) {
List<Order> orders = page.getData();
for (Order order : orders) {
//同步請(qǐng)求獲取購買者的信息
User buyer = userApi.getUserInfoById(order.getBuyer().getBuyerId());
//把獲取的購買者信息賦值給Order
order.setBuyer(buyer);
}
}
})
雖然實(shí)現(xiàn)了功能, 但是總覺得不爽, 都用了RxJava這么牛逼的框架, 還要用for循環(huán)操作. 有沒有比較優(yōu)雅的方式來實(shí)現(xiàn)這種需求呢?
**這種需求就是 對(duì)A對(duì)象上的某個(gè)List屬性進(jìn)行RxJava操作, 然后把操作的結(jié)果再重新賦給原來的A對(duì)象. **
我們知道對(duì)A對(duì)象的List進(jìn)行操作, RxJava操作后返回的就是List, 無法獲取原來的A對(duì)象, 除非我們先獲取A對(duì)象, 然后通過變量保存下, 當(dāng)處理完List后,把最終的List賦值給A對(duì)象, 這種方法還不如第一種呢? 我想的是有沒有一種途徑全程用RxJava操作符來做.
這種需求還是很多的, 比如返回一個(gè)用戶對(duì)象(User), 里面有個(gè)List屬性表示他的好友, 但是關(guān)于好友的信息只有id. 界面展示的他的好友信息.
類似這樣的需求, 需要對(duì)數(shù)據(jù)的某個(gè)子數(shù)據(jù)進(jìn)行單獨(dú)處理, 可以使用combineLatest來優(yōu)雅的實(shí)現(xiàn) :
userApi = ApiServiceFactory.createService(UserApi.class);
//獲取用戶信息
userApi.fetchUserInfo(null)
.flatMap(new Func1<User, Observable<User>>() {
@Override
public Observable<User> call(User user) {
printLog(tvLogs, "----fetch a user---- \n", getUserString(user));
return fetchFriendsInfo(user);
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<User>() {
@Override
public void call(User user) {
printLog(tvLogs, "----process his friends by id---- \n", getUserString(user));
}
}, new Action1<Throwable>() {
@Override
public void call(Throwable throwable) {
throwable.printStackTrace();
}
});
//這個(gè)方法才是實(shí)現(xiàn)的核心
private Observable<User> fetchFriendsInfo(User user) {
//保存User的數(shù)據(jù)
Observable<User> observableUser = Observable.just(user);
//對(duì)User的好友列表進(jìn)行單獨(dú)處理
Observable<List<User>> observableUsers = Observable.from(user.getFriends())
.flatMap(new Func1<User, Observable<User>>() {
@Override
public Observable<User> call(User user) {
//根據(jù)好友ID獲取更完整的信息
return userApi.fetchUserInfo(user.getId() + "");
}
})
.toList();
//對(duì)用戶User信息和他的好友信息進(jìn)行合并.
return Observable.combineLatest(observableUser, observableUsers, new Func2<User, List<User>, User>() {
@Override
public User call(User user, List<User> users) {
user.setFriends(users);
return user;
}
});
}
上面的代碼還是很簡單的, 注釋也比較詳細(xì). 大致的意思就是把User信息分為兩個(gè)部分:
一部分是User的基本信(Observable<User>
), 一部分是User好友列表(Observable<List<User>>
) 然后把兩個(gè)最終數(shù)據(jù)進(jìn)行組合就是我們最終需要的數(shù)據(jù)了.
我在github上已經(jīng)寫了相關(guān)例子, 運(yùn)行效果如下所示:
本文的例子放在github上https://github.com/chiclaim/android-sample/tree/master/rxjava