前言
封裝作為面向?qū)ο蟮娜蠡咎卣髦怀蹦酰覀冊(cè)谑褂肦xJava的時(shí)候也必然涉及到封裝哄啄。
但是Rx是一種數(shù)據(jù)流鏈?zhǔn)浇Y(jié)構(gòu)的編程思想迁霎,我們?cè)诜庋b時(shí)應(yīng)該不能打斷其鏈?zhǔn)浇Y(jié)構(gòu)肉盹。
封裝前
如果你有看過(guò)我的 使用RxJava優(yōu)雅的處理服務(wù)器返回異常 這篇簡(jiǎn)書的話,里面有類似下面這樣的代碼:
_apiService.login(mobile, verifyCode)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnTerminate(() -> hideLoadingDialog())
.flatMap(result -> {
if (result.status == RESTResult.FAILURE) {
int code = result.code;
// 根據(jù)不同code進(jìn)行不同處理
...
return Observable.error(new ServerException(result.message));
}
return Observable.just(result.data);
})
.subscribe(new Action1<User>() {
@Override
public void call(User user) {
// user對(duì)象
}
}, 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, "網(wǎng)絡(luò)不可用国拇!", Toast.LENGTH_SHORT).show();
}else{
Toast.makeText(_context, "請(qǐng)求失敗,請(qǐng)稍后重試", Toast.LENGTH_SHORT).show();
}
}
}
});
上面的代碼看起來(lái)有點(diǎn)“臟”洛史,一些地方完全可以封裝一下,比如:
1酱吝、線程的處理也殖,可以進(jìn)行封裝;
2、服務(wù)器返回格式一般都是固定的务热,對(duì)服務(wù)器返回的狀態(tài)作處理忆嗜,可以進(jìn)行封裝;
3、onError里對(duì)異常的處理陕习,可以進(jìn)行封裝.
封裝方案
1霎褐、封裝 Rx線程相關(guān)
這個(gè)我想很多小伙伴都很熟悉,使用compose()操作符该镣!
compose()里接收一個(gè)Transformer對(duì)象冻璃,Transformer繼承自Func1<Observable<T>, Observable<R>>,可以通過(guò)它將一種類型的Observable轉(zhuǎn)換成另一種類型的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、封裝 處理服務(wù)器返回?cái)?shù)據(jù)
我們把代碼里的flatMap()操作符內(nèi)的內(nèi)容嫁审,作為靜態(tài)方法提到一個(gè)Helper類里跋炕,即完成封裝。
不過(guò)我的做法有點(diǎn)不一樣律适,我還是用了compose+Transformer辐烂,在flatMap外包了一層,即:
/**
* Rx處理服務(wù)器返回
* 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())
.//省略
因?yàn)槲覀兎?wù)器的返回的數(shù)據(jù)格式一般都是一致的捂贿,所有我們每個(gè)網(wǎng)絡(luò)請(qǐng)求都可以使用compose(RxResultHelper.handleResult())
來(lái)處理服務(wù)器返回纠修。
這里我在flatMap外面包了一層compose,原因是我把封裝的部分都作為一個(gè)Transformer厂僧,這樣封裝的部分都是使用compose操作符扣草,代碼看起來(lái)更加清晰,當(dāng)然你也可以直接使用flatMap颜屠,即.flatMap(RxResultHelper.handleResult())
(handleResult方法需要更改為flatMap的Func1方法)
3辰妙、封裝 Subscriber,對(duì)異常進(jìn)行封裝
我們已經(jīng)處理服務(wù)器返回甫窟,可能有各種各樣的異常密浑,比如:
1、網(wǎng)絡(luò)異常
2粗井、服務(wù)器連接異常
3肴掷、接口請(qǐng)求參數(shù)等異常
我們可以封裝一個(gè)Subscriber對(duì)其進(jìn)行預(yù)處理敬锐,讓調(diào)用者只需關(guān)心是Log還是Toast錯(cuò)誤消息等行為即可。
/**
* 封裝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) {
// 服務(wù)器異常
msg = e.getMessage();
} else if(e instanceof ReloginException){
// 踢出登錄
}else if (throwable instanceof UnknownHostException) {
msg = "沒(méi)有網(wǎng)絡(luò)...";
} else if (throwable instanceof SocketTimeoutException) {
// 超時(shí)
msg = "超時(shí)...";
}else{
msg = "請(qǐng)求失敗呆瞻,請(qǐng)稍后重試...");
}
_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之后,我們?cè)趏nNext里只關(guān)心對(duì)數(shù)據(jù)的處理径玖,在onError里只關(guān)心發(fā)生異常該做哪些后續(xù)操作即可痴脾。
封裝后
最后我們?cè)倏聪陆?jīng)過(guò)我們的封裝后,文章開頭的那塊“臟”代碼會(huì)變成下面這樣:
_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);
});
是不是神清氣爽了呢梳星?赞赖!
當(dāng)然不僅這里的代碼會(huì)變得簡(jiǎn)潔,所有使用Rx處理網(wǎng)絡(luò)的代碼都可以使用上面3個(gè)RxHelper類冤灾,小伙伴們可隨意定制和拓展~