這里的網(wǎng)絡(luò)請求部分在我的另一篇文章Retrofit + OkHttp3 + RxJava2中进统,后面用到的
Retrofits
坡锡、Api
都是來自該項(xiàng)目的一些Demo這里記錄一些最近開發(fā)的想法和思路,一步一步是怎么實(shí)現(xiàn)一個(gè)簡單功能院溺,并去考慮拓展楣嘁,逐步完善的過程。下面的需求實(shí)際是我自己的不斷考慮和改變的一個(gè)過程覆获,用來展示RxJava的一些優(yōu)勢马澈。實(shí)際項(xiàng)目開發(fā)中這些應(yīng)該提前就考慮到,但是需求總是變化的弄息,這些優(yōu)勢也或多或少的會(huì)有價(jià)值痊班。希望看完這篇文章你會(huì)有收獲。
開始
請求一個(gè)網(wǎng)絡(luò)結(jié)果并展示在View
接Retrofit + OkHttp3 + RxJava2中的例子
Retrofit配置中默認(rèn)網(wǎng)絡(luò)請求在IO線程
TextView showView;
...
Retrofits.get(Api.class)
.getServerInfo()
//指定訂閱者在UI線程響應(yīng)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {
showView.setText(result.toString());
});
異常抓取
這里用到了onErrorReturn
關(guān)鍵字摹量,其作用就是當(dāng)錯(cuò)誤發(fā)生的時(shí)候返回一個(gè)默認(rèn)值給訂閱者涤伐。
Return的數(shù)據(jù)必須為Observable的數(shù)據(jù)類型,在Retrofits返回?cái)?shù)據(jù)中為Observable<BaseResult<T>>缨称,這里需要返回一個(gè)BaseResult<T>凝果,攜帶錯(cuò)誤信息
需求:網(wǎng)絡(luò)無法連接code1001,連接超時(shí)code為1002睦尽,解析錯(cuò)誤code為1100
這里新建一個(gè)工具類Observables器净。
public class Observables {
public static <T> Function<Throwable, BaseResult<T>> getErrorReturn() {
return throwable -> {
BaseResult<T> result = new BaseResult<>();
if (throwable instanceof ConnectException ) {
result.setCode(1001);
result.setMessage("無法訪問服務(wù)器");
} else if (throwable instanceof SocketTimeoutException) {
result.setCode(1002);
result.setMessage("連接超時(shí)");
} else if (throwable instanceof JsonParseException) {
result.setCode(1100);
result.setMessage("解析失敗");
}
return result;
};
}
.....
}
添加到業(yè)務(wù)處理
TextView showView;
...
Retrofits.get(Api.class)
.getServerInfo()
.onErrorReturn(Observables.getErrorReturn())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {
showView.setText(result.toString());
});
這里當(dāng)產(chǎn)生這3個(gè)Exception后就能直接返回錯(cuò)誤碼,方便上層處理
綁定生命周期
在很多異步處理請求中当凡,我們都需要判斷當(dāng)數(shù)據(jù)請求返回后山害,是否我當(dāng)前的頁面被銷毀,如果不做判斷直接使用會(huì)出現(xiàn)崩潰或者內(nèi)存泄露沿量。
思路:
- 對Acitivy或者Fragment在生命周期做一個(gè)Observable當(dāng)生命周期改變的時(shí)候就發(fā)射當(dāng)前的狀態(tài)
- 篩選生命周期的數(shù)據(jù)只發(fā)射結(jié)束的那一個(gè)數(shù)據(jù)
- 使用
takeUntil
關(guān)鍵字浪慌,當(dāng)takeUntil
設(shè)置的Observable
發(fā)射任何一個(gè)數(shù)據(jù)時(shí)候,就取消訂閱
核心代碼(已Fragment為例)
static final int INIT = 0;
static final int RELEASE = 1;
Observable<Integer> mLife = BehaviorSubject.create();
...
...
@Override
public void onDestroyView() {
mLife.onNext(RELEASE);
super.onDestroyView();
}
Retrofits.get(Api.class)
.getServerInfo()
.onErrorReturn(getErrorReturn())
//綁定生命周期
.takeUntil(mLife.filter(state -> state == RELEASE))
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {
showView.setText(result.toString());
});
我的另一個(gè)項(xiàng)目RxApp實(shí)現(xiàn)了該功能朴则,這里就直接使用权纤。
Retrofits.get(Api.class)
.getServerInfo()
.onErrorReturn(getErrorReturn())
//綁定生命周期
.compose(RxApp.with(this).bindLife())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {
showView.setText(result.toString());
});
綁定一個(gè)Dialog
需求
- 在開始請求時(shí)顯示Dialog
- Dialog不可取消
- 網(wǎng)絡(luò)請求結(jié)束關(guān)閉
這里用到關(guān)鍵字doOnLifecycle(final Consumer<? super Disposable> onSubscribe, final Action onDispose)
,用于在訂閱和取消訂閱的時(shí)候進(jìn)行回調(diào)。
需要注意的是
doOnLifecycle
并沒有默認(rèn)的線程調(diào)度器汹想,需要指定調(diào)度器在UI主線程
添加到工具類
public class Observables {
...
public static <T> ObservableTransformer<T, T> bindDialog(Context context) {
//具體樣式就不詳述了
final Dialog dialog = new ProgressDialog(context);
dialog.setCancelable(false);
return upstream -> upstream.doOnLifecycle(disposable -> dialog.show(), dialog::dismiss)
//設(shè)置在UI主線程執(zhí)行
.subscribeOn(AndroidSchedulers.mainThread());
}
}
使用
Retrofits.get(Api.class)
.getServerInfo()
.onErrorReturn(getErrorReturn())
//綁定Dialog
.compose(Observables.bindDialog(getActivity()))
.compose(RxApp.with(this).bindLife())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {
showView.setText(result.toString());
});
Dialog可取消同時(shí)取消請求
同樣使用關(guān)鍵字takeUntil
來處理該流程
public class Observables {
...
public static <T> ObservableTransformer<T, T> bindCancelDialog(Context context) {
final Dialog dialog = new ProgressDialog(context);
dialog.setCancelable(true);
dialog.setCanceledOnTouchOutside(false);
//定義取消觸發(fā)的Observable
BehaviorSubject<Boolean> dialogCancelSubject = BehaviorSubject.create();
dialog.setOnCancelListener(dialog1 -> dialogCancelSubject.onNext(true));
return upstream -> upstream.doOnLifecycle(disposable ->dialog.show(),dialog::dismiss)
.subscribeOn(AndroidSchedulers.mainThread())
.takeUntil(dialogCancelSubject);
}
}
使用
Retrofits.get(Api.class)
.getServerInfo()
.onErrorReturn(getErrorReturn())
//綁定Dialog
.compose(Observables.bindDialog(getActivity()))
.compose(RxApp.with(this).bindLife())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {
showView.setText(result.toString());
});
Dialog 2秒后可取消
使用Observable.timer
來實(shí)現(xiàn)
public class Observables {
...
public static <T> ObservableTransformer<T, T> bindCancelDialog(Context context) {
final Dialog dialog = new ProgressDialog(context);
dialog.setCancelable(true);
dialog.setCanceledOnTouchOutside(false);
BehaviorSubject<Boolean> dialogCancelSubject = BehaviorSubject.create();
dialog.setOnCancelListener(dialog1 -> dialogCancelSubject.onNext(true));
return upstream -> upstream.doOnLifecycle(disposable -> {
dialog.show();
Observable.timer(2, TimeUnit.SECONDS)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(time -> {
if(dialog.isShowing()){
Toast.makeText(context,"點(diǎn)擊返回可取消",Toast.LENGTH_SHORT).show();
dialog.setCancelable(true);
}
});
},
dialog::dismiss)
.subscribeOn(AndroidSchedulers.mainThread())
.takeUntil(dialogCancelSubject);
}
}
總結(jié)
上面介紹了如何從一個(gè)簡單的網(wǎng)絡(luò)外邓,到添加一系列的業(yè)務(wù)處理。不難發(fā)現(xiàn)RxJava優(yōu)勢古掏,
- 代碼流程看起來聚合很高坐榆,而且很易讀懂(前提是你了解Rxjava的關(guān)鍵字的作用)
- 在業(yè)務(wù)中間添加流程很簡單,方便以后的維護(hù)
- 解耦很方便冗茸,很多功能性的處理我們可以直接提出成工具類席镀,使用
compose
進(jìn)行批量處理
好了就分享這么多,希望對大家有幫助夏漱。