前言
封裝作為面向對象的三大基本特征之一,我們在使用RxJava的時候也必然涉及到封裝。
但是Rx是一種數據流鏈式結構的編程思想,我們在封裝時應該不能打斷其鏈式結構。
封裝前
如果你有看過我的 使用RxJava優雅的處理服務器返回異常 這篇簡書的話,里面有類似下面這樣的代碼:
_apiService.login(mobile, verifyCode)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnTerminate(() -> hideLoadingDialog())
.flatMap(result -> {
if (result.status == RESTResult.FAILURE) {
int code = result.code;
// 根據不同code進行不同處理
...
return Observable.error(new ServerException(result.message));
}
return Observable.just(result.data);
})
.subscribe(new Action1<User>() {
@Override
public void call(User user) {
// user對象
}
}, new Action1<Throwable>() {
@Override
public void call(Throwable throwable) {
throwable.printStackTrace();
if (e instanceof ServerException){
Toast.makeText(_context, e.getMessage(), Toast.LENGTH_SHORT).show();
} else{
if (!NetUtil.checkNet(MyApplication.getInstance())) {
Toast.makeText(_context, "網絡不可用!", Toast.LENGTH_SHORT).show();
}else{
Toast.makeText(_context, "請求失敗,請稍后重試", Toast.LENGTH_SHORT).show();
}
}
}
});
上面的代碼看起來有點“臟”,一些地方完全可以封裝一下,比如:
1、線程的處理,可以進行封裝;
2、服務器返回格式一般都是固定的,對服務器返回的狀態作處理,可以進行封裝;
3、onError里對異常的處理,可以進行封裝.
封裝方案
1、封裝 Rx線程相關
這個我想很多小伙伴都很熟悉,使用compose()操作符!
compose()里接收一個Transformer對象,Transformer繼承自Func1<Observable<T>, Observable<R>>,可以通過它將一種類型的Observable轉換成另一種類型的Observable。
下面是我的RxSchedulersHelper:
/**
* 處理Rx線程
* Created by YoKey.
*/
public class RxSchedulersHelper {
public static <T> Observable.Transformer<T, T> io_main() {
return new Observable.Transformer<T, T>() {
@Override
public Observable<T> call(Observable<T> tObservable) {
return tObservable
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
}
};
}
}
使用前:
_apiService.login(mobile, verifyCode)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.//省略
使用后:
_apiService.login(mobile, verifyCode)
.compose(RxSchedulersHelper.io_main())
.//省略
以后任何使用
.subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread())
的地方都可以使用.compose(RxSchedulersHelper.io_main())
代替啦。
2、封裝 處理服務器返回數據
我們把代碼里的flatMap()操作符內的內容,作為靜態方法提到一個Helper類里,即完成封裝。
不過我的做法有點不一樣,我還是用了compose+Transformer,在flatMap外包了一層,即:
/**
* Rx處理服務器返回
* Created by YoKey.
*/
public class RxResultHelper {
public static <T> Observable.Transformer<RESTResult<T>, T> handleResult() {
return new Observable.Transformer<RESTResult<T>, T>() {
@Override
public Observable<T> call(Observable<RESTResult<T>> tObservable) {
return tObservable.flatMap(
new Func1<RESTResult<T>, Observable<T>>() {
@Override
public Observable<T> call(RESTResult<T> result) {
if (result.status == RESTResult.SUCCESS) {
return Observable.just(result.getData());
} else if (result.status == RESTResult.SIGN_OUT) {
// 處理被踢出登錄情況
return Observable.error(new ReloginException());
} else {
return Observable.error(new ServerException(result.message));
}
return Observable.empty();
}
}
);
}
};
}
}
使用后:
_apiService.login(mobile, verifyCode)
.compose(RxSchedulersHelper.io_main())
.compose(RxResultHelper.handleResult())
.//省略
因為我們服務器的返回的數據格式一般都是一致的,所有我們每個網絡請求都可以使用compose(RxResultHelper.handleResult())
來處理服務器返回。
這里我在flatMap外面包了一層compose,原因是我把封裝的部分都作為一個Transformer,這樣封裝的部分都是使用compose操作符,代碼看起來更加清晰,當然你也可以直接使用flatMap,即.flatMap(RxResultHelper.handleResult())
(handleResult方法需要更改為flatMap的Func1方法)
3、封裝 Subscriber,對異常進行封裝
我們已經處理服務器返回,可能有各種各樣的異常,比如:
1、網絡異常
2、服務器連接異常
3、接口請求參數等異常
我們可以封裝一個Subscriber對其進行預處理,讓調用者只需關心是Log還是Toast錯誤消息等行為即可。
/**
* 封裝Subscriber
* Created by YoKey.
*/
public abstract class RxSubscriber<T> extends Subscriber<T> {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
e.printStackTrace();
if (e instanceof ServerException) {
// 服務器異常
msg = e.getMessage();
} else if(e instanceof ReloginException){
// 踢出登錄
}else if (throwable instanceof UnknownHostException) {
msg = "沒有網絡...";
} else if (throwable instanceof SocketTimeoutException) {
// 超時
msg = "超時...";
}else{
msg = "請求失敗,請稍后重試...");
}
_onError(msg);
}
@Override
public void onNext(T t) {
_onNext(t);
}
public abstract void _onNext(T t);
public abstract void _onError(String msg);
}
使用后:
_apiService.login(mobile, verifyCode)
.//省略
.subscribe(new RxSubscriber<User user>() {
@Override
public void _onNext(User user) {
// 處理user
}
@Override
public void _onError(String msg) {
ToastUtil.showShort(mActivity, msg);
});
這樣使用RxSubscriber之后,我們在onNext里只關心對數據的處理,在onError里只關心發生異常該做哪些后續操作即可。
封裝后
最后我們再看下經過我們的封裝后,文章開頭的那塊“臟”代碼會變成下面這樣:
_apiService.login(mobile, verifyCode)
.compose(RxSchedulersHelper.io_main())
.compose(RxResultHelper.handleResult())
.doOnTerminate(() -> hideLoadingDialog())
.subscribe(new RxSubscriber<User user>() {
@Override
public void _onNext(User user) {
// 處理user
}
@Override
public void _onError(String msg) {
ToastUtil.showShort(mActivity, msg);
});
是不是神清氣爽了呢?!
當然不僅這里的代碼會變得簡潔,所有使用Rx處理網絡的代碼都可以使用上面3個RxHelper類,小伙伴們可隨意定制和拓展~