編輯:關於Android編程
switchIfEmpty(Observable emptyObservable)操作符從字面意思上就很好理解,就是當為空的時候跳轉到emptyObservable。
那麼如何理解當為空的時候. 下面將會使用實際案例解釋這個switchIfEmpty的使用方法。
假如我們的app裡有加載文章列表功能,要求加載的邏輯如下:加載文章的的時候,先從本地加載,如果本地存在就是用本地的數據,如果不存在從網絡獲取。
下面是業務代碼:
//從本地數據獲取文章列表
getArticlesObservable(pageIndex, pageSize, categoryId)
//本地不存在,請求api
.switchIfEmpty(articleApi.getArticlesByCategoryId(pageIndex + "", pageSize + "", categoryId + "")
.compose(this.handlerResult())
.flatMap(new Func1>() {
@Override
public Observable 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對成功、失敗的數據處理,然後統一把數據推給上一層,就不用每個地方都寫下面相同的模板代碼了:
observable.subscribe(new Action1() { @Override public void call(RespArticlePaginate respArticlePaginate) { //success data } }, new Action1 () { @Override public void call(Throwable throwable) { // error data } })
那麼createSubscriber是如何實現的,先看subscribe方法源碼 如下:
public final Subscription subscribe(final Action1 onNext, final Action1 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(onNext, onError, onCompleted));
}
很簡單,他是直接new了一個ActionSubscriber,然後把我們以前在代碼裡寫的各個回調(onNext、onError、onComplete)當做參數傳遞進去。那麼我們的createSubscriber也可以模擬它的實現:
/**
* 處理結果(分發結果) 封裝
*
* @param id 區分業務類型
*/
protected ActionSubscriber createSubscriber(final int id) {
//因為我們只關心onNext和onError
Action0 onCompleted = Actions.empty();
return new ActionSubscriber(new Action1() {
@Override
public void call(T t) {
pushSuccessData(id, t);
}
}, new Action1() {
@Override
public void call(Throwable throwable) {
pushThrowable(id, throwable);
}
}, onCompleted);
}
好了,言歸正傳,回到我們上面提到的需求。根據需求我們來分析下代碼:
getArticlesObservable方法用來從本地獲取文章列表,articleApi.getArticlesByCategoryId方法是用來當本地不存在的時候從網絡獲取。似乎這些代碼可以實現了我們上面提到的需求了。而且很簡潔。
實踐是檢驗真理的唯一標准,我們先運行下看看(本地環境是數據庫沒有文章列表)。
運行後,發現界面並沒有展示數據,通過debug返現,代碼執行了檢測本地緩存的邏輯,且本地找不到符合邏輯的數據,也就是說從本地找到的結果為空。但是沒有按照我們預想的是執行網絡請求。
先來看看查詢本地緩存的代碼是是什麼樣子。
Observable.create(new Observable.OnSubscribe
通過debug發現代碼走的邏輯是
if (as == null || as.isEmpty()) {
subscriber.onNext(null);
}
發送的是空,為什麼還是沒有走switchIfEmpty裡的邏輯呢?肯定是我們用的姿勢不對,先看看該該方法的說明:
/**
* 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.
*
*
*
Scheduler:
*
{@code switchIfEmpty} does not operate by default on a particular {@link Scheduler}.
*
* * @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 switchIfEmpty(Observablealternate) { return lift(new OperatorSwitchIfEmpty(alternate)); }
重點關注對參數Observablealternate的解釋:
the alternate Observable to subscribe to if the source does not emit any items
意思是如果原來的Observable沒有發射任何數據(emit any items),則使用alternate代替原來的Observable。
好,再看看我們的代碼邏輯:
if (as == null || as.isEmpty()) {
subscriber.onNext(null);
}
這段代碼不是沒有發射數據,而是發射了個空數據,也就是發射了null,所以這段代碼並不是沒有發射任何數據,所以為什麼不走網絡請求的邏輯。
知道原因就好解決了,加上個過濾就可以解決問題了:
.filter(new Func1() { @Override public Boolean call(RespArticlePaginate respArticlePaginate) { return respArticlePaginate != null; } })
1,通過switchIfEmpty可以做到一些邏輯判斷,當然實現類型的判斷本地緩存的,可以通過concat結合takeFirst操作符來實現,具體的可以看我以前的博客文章
2,上面通過Observable.create方式來包裝數據查詢,不是很優雅。下一篇博客介紹如何封裝RxJava,使得我們的代碼支持RxJava鏈式調用。
從源碼的角度理解四大組件的工作過程——Android開發藝術探索筆記
系統對四大組件的過程進行了很大程度的封裝,日常開發中並不需要了解底層的工作原理,那麼研究這些原理的意義在哪裡呢?如果你想在技術上更進一步,那麼了解一些系統的工作原理是十分
Android5.0多種側滑欄效果實例代碼
1.普通側滑效果圖: 思路:通過自定義View繼承HorizontalScrollView,然後重寫onMeasure(),onLayout(),onTouch
Android SQLite數據庫使用示例
簡單介紹一下,現在的主流移動設備像Android、iPhone等都使用SQLite作為復雜數據的存儲引擎,在我們為移動設備開發應用程序時,也許就要使用到SQLite來存儲
Android對話框(一)AlertDialog
最近在做項目,小組幾個回了家。界面暫時沒人做,用到自定義對話框只能臨時去學。現在把對話框的相關整理。 +