本文主要探究用Rxjava2 + Retrofit進(jìn)行網(wǎng)絡(luò)請(qǐng)求時(shí), 應(yīng)該在哪里調(diào)用 showLoading()
, 在哪里調(diào)用 hideLoading()
.
別告訴我, 你是這樣調(diào)用的....
//網(wǎng)絡(luò)請(qǐng)求獲取用戶信息
showLoading();
API.getUserInfo()
....
.subscribe((integer -> {
hideLoading();
//dosomething
...
}, e -> {
hideLoading();
//handle error
...
});
當(dāng)然也無(wú)妨, 只不過(guò)丑了點(diǎn)... 這里, 我們用doXXX
操作符優(yōu)雅的解決這個(gè)問(wèn)題.
首先探究下各種 doXXX
操作符的執(zhí)行時(shí)機(jī): (類似于聲明周期)
1. 正常執(zhí)行
測(cè)試代碼
Observable.create(emiter -> {
emiter.onNext(1);
emiter.onComplete();
})
.doOnSubscribe(d -> LOG.d(TAG, "doOnSubscribe"))
.doOnNext(integer -> LOG.d(TAG, "doOnNext"))
.doAfterNext(integer -> LOG.d(TAG, "doAfterNext"))
.doOnComplete(() -> LOG.d(TAG, "doOnComplete"))
.doOnError(throwable -> LOG.d(TAG, "doOnError"))
.doOnTerminate(() -> LOG.d(TAG, "doOnTerminate"))
.doAfterTerminate(() -> LOG.d(TAG, "doAfterTerminate"))
.doFinally(() -> LOG.d(TAG, "doFinally"))
.doOnDispose(() -> LOG.d(TAG, "doOnDispose"))
.subscribe(integer -> {
LOG.d(TAG, "onNext");
}, e -> {
LOG.d(TAG, "onError");
}, () -> {
LOG.d(TAG, "onComplete");
});
結(jié)果
// doOnSubscribe
// doOnNext
// onNext
// doAfterNext
// doOnComplete
// doOnTerminate
// onComplete
// doFinally
// doAfterTerminate
2. 上游拋異常
測(cè)試代碼
Observable.create(emiter -> {
emiter.onError(new NullPointerException());
})
.doOnSubscribe(d -> LOG.d(TAG, "doOnSubscribe"))
.doOnNext(integer -> LOG.d(TAG, "doOnNext"))
.doAfterNext(integer -> LOG.d(TAG, "doAfterNext"))
.doOnComplete(() -> LOG.d(TAG, "doOnComplete"))
.doOnError(throwable -> LOG.d(TAG, "doOnError"))
.doOnTerminate(() -> LOG.d(TAG, "doOnTerminate"))
.doAfterTerminate(() -> LOG.d(TAG, "doAfterTerminate"))
.doFinally(() -> LOG.d(TAG, "doFinally"))
.doOnDispose(() -> LOG.d(TAG, "doOnDispose"))
.subscribe((integer -> {
LOG.d(TAG, "onNext");
}, e -> {
LOG.d(TAG, "onError");
}, () -> {
LOG.d(TAG, "onComplete");
}));
結(jié)果
// doOnSubscribe
// doOnError
// doOnTerminate
// onError
// doFinally
// doAfterTerminate
根據(jù)以上執(zhí)行結(jié)果可以看出, 不管是正常執(zhí)行還是上游拋出異常,
開始都會(huì)調(diào)用doOnSubscribe
,
結(jié)束都會(huì)調(diào)用doOnTerminate
,doFinally
,doAfterTerminate
.
那么是不是我們可以從以上三個(gè)方法中隨便選一個(gè)作為結(jié)束的節(jié)點(diǎn), 調(diào)用hideLoading()
就可以呢?
非也! 下面來(lái)看一個(gè)很多人容易忽略的問(wèn)題, 在下游的 onNext()
方法中拋出異常,
3. 下游 onNext 拋異常
測(cè)試代碼
Observable.create(emiter -> {
emiter.onNext(1);
emiter.onComplete();
})
.doOnSubscribe(d -> LOG.d(TAG, "doOnSubscribe"))
.doOnNext(integer -> LOG.d(TAG, "doOnNext"))
.doAfterNext(integer -> LOG.d(TAG, "doAfterNext"))
.doOnComplete(() -> LOG.d(TAG, "doOnComplete"))
.doOnError(throwable -> LOG.d(TAG, "doOnError"))
.doOnTerminate(() -> LOG.d(TAG, "doOnTerminate"))
.doAfterTerminate(() -> LOG.d(TAG, "doAfterTerminate"))
.doFinally(() -> LOG.d(TAG, "doFinally"))
.doOnDispose(() -> LOG.d(TAG, "doOnDispose"))
.subscribe(integer -> {
LOG.d(TAG, "onNext");
throw new NullPointerException(); //此處拋出異常
}, e -> {
LOG.d(TAG, "onError");
}, () -> {
LOG.d(TAG, "onComplete");
});
結(jié)果
// doOnSubscribe
// doOnNext
// onNext
// doOnDispose
// doFinally
// onError
// doAfterNext
在onNext()
中拋出異常就是你的業(yè)務(wù)邏輯中報(bào)錯(cuò)了, 此時(shí)會(huì)調(diào)用onError()
, 但不會(huì)調(diào)用doOnError
, doOnTerminate
和 doAfterTerminate
.
所以如果你選擇了doOnTerminate
或者 doAfterTerminate
作為了你的結(jié)束節(jié)點(diǎn), 那么就可能會(huì)出現(xiàn)loading顯示后無(wú)法隱藏的問(wèn)題..
綜上, 我們找到了整個(gè)事件的首尾節(jié)點(diǎn):
開始必然執(zhí)行doOnSubscribe
結(jié)束必然執(zhí)行doFinally
優(yōu)雅的方式:
//網(wǎng)絡(luò)請(qǐng)求獲取用戶信息
API.getUserInfo()
.doOnSubscribe(d -> showLoading())
.doFinally(() -> hideLoading())
.subscribe((integer -> {
//dosomething
}, e -> {
//handle error
});