switchIfEmpty(Observable emptyObservable)操作符從字面意思上就很好理解,就是當(dāng)為空的時(shí)候跳轉(zhuǎn)到emptyObservable。
那末如何理解當(dāng)為空的時(shí)候
. 下面將會(huì)使用實(shí)際案例解釋這個(gè)switchIfEmpty
的使用方法。
假設(shè)我們的app里有加載文章列表功能,要求加載的邏輯以下:加載文章的的時(shí)候,先從本地加載,如果本地存在就是用本地的數(shù)據(jù),如果不存在從網(wǎng)絡(luò)獲得。
下面是業(yè)務(wù)代碼:
//從本地?cái)?shù)據(jù)獲得文章列表
getArticlesObservable(pageIndex, pageSize, categoryId)
//本地不存在,要求api
.switchIfEmpty(articleApi.getArticlesByCategoryId(pageIndex + "", pageSize + "", categoryId + "")
.compose(this.<RespArticlePaginate>handlerResult())
.flatMap(new Func1<RespArticlePaginate, Observable<RespArticlePaginate>>() {
@Override
public Observable<RespArticlePaginate> call(RespArticlePaginate respArticlePaginate) {
if (respArticlePaginate != null && respArticlePaginate.getList() != null) {
try {
articleDao.insertOrReplaceInTx(respArticlePaginate.getList());
} catch (Exception e) {
e.printStackTrace();
}
}
return Observable.just(respArticlePaginate);
}
}))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(createSubscriber(ID_ARTICLE_LIST)))
這里的 createSubscriber
封裝了Subscriber對(duì)成功、失敗的數(shù)據(jù)處理,然后統(tǒng)1把數(shù)據(jù)推給上1層,就不用每一個(gè)地方都寫下面相同的模板代碼了:
observable.subscribe(new Action1<RespArticlePaginate>() {
@Override
public void call(RespArticlePaginate respArticlePaginate) {
//success data
}
}, new Action1<Throwable>() {
@Override
public void call(Throwable throwable) {
// error data
}
})
那末createSubscriber
是如何實(shí)現(xiàn)的,先看subscribe方法源碼 以下:
public final Subscription subscribe(final Action1<? super T> onNext, final Action1<Throwable> onError) {
if (onNext == null) {
throw new IllegalArgumentException("onNext can not be null");
}
if (onError == null) {
throw new IllegalArgumentException("onError can not be null");
}
Action0 onCompleted = Actions.empty();
return subscribe(new ActionSubscriber<T>(onNext, onError, onCompleted));
}
很簡單,他是直接new了1個(gè)ActionSubscriber,然后把我們之前在代碼里寫的各個(gè)回調(diào)(onNext、onError、onComplete)當(dāng)作參數(shù)傳遞進(jìn)去。那末我們的createSubscriber
也能夠摹擬它的實(shí)現(xiàn):
/**
* 處理結(jié)果(分發(fā)結(jié)果) 封裝
*
* @param id 辨別業(yè)務(wù)類型
*/
protected <T> ActionSubscriber<T> createSubscriber(final int id) {
//由于我們只關(guān)心onNext和onError
Action0 onCompleted = Actions.empty();
return new ActionSubscriber<T>(new Action1<T>() {
@Override
public void call(T t) {
pushSuccessData(id, t);
}
}, new Action1<Throwable>() {
@Override
public void call(Throwable throwable) {
pushThrowable(id, throwable);
}
}, onCompleted);
}
好了,言歸正傳,回到我們上面提到的需求。根據(jù)需求我們來分析下代碼:
getArticlesObservable
方法用來從本地獲得文章列表,articleApi.getArticlesByCategoryId
方法是用來當(dāng)本地不存在的時(shí)候從網(wǎng)絡(luò)獲得。仿佛這些代碼可以實(shí)現(xiàn)了我們上面提到的需求了。而且很簡潔。
實(shí)踐是檢驗(yàn)真諦的唯1標(biāo)準(zhǔn),我們先運(yùn)行下看看(本地環(huán)境是數(shù)據(jù)庫沒有文章列表)。
運(yùn)行后,發(fā)現(xiàn)界面并沒有展現(xiàn)數(shù)據(jù),通過debug返現(xiàn),代碼履行了檢測(cè)本地緩存的邏輯,且本地找不到符合邏輯的數(shù)據(jù),也就是說從本地找到的結(jié)果為空。但是沒有依照我們料想的是履行網(wǎng)絡(luò)要求。
先來看看查詢本地緩存的代碼是是甚么模樣。
Observable.create(new Observable.OnSubscribe<Object>() {
@Override
public void call(Subscriber<? super Object> subscriber) {
try {
List<Article> as = articleDao.queryBuilder()
.where(ArticleDao.Properties.CategoryId.eq(categoryId))
.orderDesc(ArticleDao.Properties.Id)
.offset((pageIndex - 1) * pageSize)
.limit(pageSize).list();
if (as == null || as.isEmpty()) {
subscriber.onNext(null);
}else{
subscriber.onNext(as);
}
}catch (Exception e){
subscriber.onError(e);
}
subscriber.onCompleted();
}
});
通過debug發(fā)現(xiàn)代碼走的邏輯是
if (as == null || as.isEmpty()) {
subscriber.onNext(null);
}
發(fā)送的是空,為何還是沒有走switchIfEmpty里的邏輯呢?肯定是我們用的姿式不對(duì),先看看該該方法的說明:
/**
* Returns an Observable that emits the items emitted by the source Observable or the items of an alternate
* Observable if the source Observable is empty.
* <p/>
* <dl>
* <dt><b>Scheduler:</b></dt>
* <dd>{@code switchIfEmpty} does not operate by default on a particular {@link Scheduler}.</dd>
* </dl>
*
* @param alternate
* the alternate Observable to subscribe to if the source does not emit any items
* @return an Observable that emits the items emitted by the source Observable or the items of an
* alternate Observable if the source Observable is empty.
* @since 1.1.0
*/
public final Observable<T> switchIfEmpty(Observable<? extends T> alternate) {
return lift(new OperatorSwitchIfEmpty<T>(alternate));
}
重點(diǎn)關(guān)注對(duì)參數(shù)Observable<? extends T> alternate
的解釋:
the alternate Observable to subscribe to if the source does not emit any items
意思是如果原來的Observable沒有發(fā)射任何數(shù)據(jù)(emit any items),則使用alternate
代替原來的Observable。
好,再看看我們的代碼邏輯:
if (as == null || as.isEmpty()) {
subscriber.onNext(null);
}
這段代碼不是沒有發(fā)射數(shù)據(jù),而是發(fā)射了個(gè)空數(shù)據(jù),也就是發(fā)射了null,所以這段代碼其實(shí)不是沒有發(fā)射任何數(shù)據(jù),所以為何不走網(wǎng)絡(luò)要求的邏輯。
知道緣由就好解決了,加上個(gè)過濾就能夠解決問題了:
.filter(new Func1<RespArticlePaginate, Boolean>() {
@Override
public Boolean call(RespArticlePaginate respArticlePaginate) {
return respArticlePaginate != null;
}
})
1,通過switchIfEmpty可以做到1些邏輯判斷,固然實(shí)現(xiàn)類型的判斷本地緩存的,可以通過concat
結(jié)合takeFirst
操作符來實(shí)現(xiàn),具體的可以看我之前的博客文章
2,上面通過Observable.create方式來包裝數(shù)據(jù)查詢,不是很優(yōu)雅。下1篇博客介紹如何封裝RxJava,使得我們的代碼支持RxJava鏈?zhǔn)秸{(diào)用。