前言
封装作为面向对象的三大基本特征之一,我们在使用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() {
@Override
public void call(User user) {
// user对象
}
}, new Action1() {
@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
下面是我的RxSchedulersHelper:
/**
* 处理Rx线程
* Created by YoKey.
*/
public class RxSchedulersHelper {
public static Observable.Transformer io_main() {
return new Observable.Transformer() {
@Override
public Observable call(Observable 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 Observable.Transformer, T> handleResult() {
return new Observable.Transformer, T>() {
@Override
public Observable call(Observable> tObservable) {
return tObservable.flatMap(
new Func1, Observable>() {
@Override
public Observable call(RESTResult 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 extends Subscriber {
@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() {
@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() {
@Override
public void _onNext(User user) {
// 处理user
}
@Override
public void _onError(String msg) {
ToastUtil.showShort(mActivity, msg);
});
是不是神清气爽了呢?!
当然不仅这里的代码会变得简洁,所有使用Rx处理网络的代码都可以使用上面3个RxHelper类,小伙伴们可随意定制和拓展~
参考资料:
小鄧子:【译】避免打断链式结构:使用.compose( )操作符