在使用 RxJava+Retrofit
结合的网络框架时,为了避免打破流式调用 和 过于繁杂的 Subscribe
代码
我们做了很多的尝试,比如 自定义操作符
,自定义Transformer
,泛型处理
,和 自定义 Subscriber
等
比如,在服务器返回数据中,假设服务器遵循规范,返回报文一般类似下面这种,
{
"success": false, // 是否成功
"code": "500", // 响应码
"data": {
// 内容,错误的时候返回""
}
}
这时候,我们我们的 JavaBean
是这样的,
public class Response<T> {
public boolean success;
public String code;
public T data;
}
这种错误 code
是我们和服务器约定好的,称为异常,即网络访问成功了.
但是还有一种错误 即: http 错误,比如典型的
Retrofit中的 retrofit cache 504 Unsatisfiable Request (only-if-cached) error
错误.这两种我们都必须处理.
接下来 根据Retrofit+RxJava 优雅的处理服务器返回异常、错误的介绍来进行了一系列的处理,
首先定义如下Transformer
转换器
public static <T> Observable.Transformer<Response<T>, T> sTransformer() {
return responseObservable -> responseObservable.map(tResponse -> {
if (!tResponse.success) throw new RuntimeException(tResponse.code);
return tResponse.data;
});
}
public static <T> Observable.Transformer<T, T> switchSchedulers() {
return observable -> observable.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
}
在真正调用的地方就可以这样写了
public void login(View v){
apiservice.login(name,pwd)
.compose(Transformers.sTransformer())
.compose(Transformers.switchSchedulers())
.subscribe(subscriber);
}
private Subscriber<UserModel> subscriber = new Subscriber<UserModel>() {
@Override public void onCompleted() {
// do onCompleted
}
@Override public void onError(Throwable e) {
// do on success != true;
// do on http error
// do on other error
}
@Override public void onNext(UserModel model) {
// parse data
}
};
其中我们的接口类似下面这样
public interface Api {
@FormUrlEncoded @POST("interface?login")
Observable<Response<UserModel>> login(@Field("name") String name,@Field("pwd") String pwd);
}
如上的处理,我们定义了 一个 sTransformer
和一个 HttpResponseFunc
,
从中我们可以明显感觉的到sTransformer
其实也是可以用Func1
来定义的,
public void login(View v){
apiservice.login(name,pwd)
.compose(Transformers.switchSchedulers())
.map(new TransFuc<UserModel>())
.onErrorReturn(new HttpResponseFunc<>())
.subscribe(subscriber);
}
public static class TransFuc<T> implements Func1<Response<T>, T> {
@Override public T call(Response<T> tResponse) {
if (!tResponse.success) throw new RuntimeException(tResponse.code);
return tResponse.data;
}
}
Transformer
作用于整个流,Func1
是一个操作符,作用于数据项
有时候服务器返回的数据并不是十分规范的,比如
正常返回是这样的
{
"success": true, // 是否成功
"status": "1", // 状态码
"data": {
// 内容
}
}
错误时时这样的
{
"success": false, // 是否成功
"status": "0", // 状态码
"data": "371" //错误码
}
针对这种数据,我们的泛型该怎么写成了问题,错误的时候是String
,正确的时候是Bean
?
这时候只能将泛型写成String
来处理了,于是乎,我们的请求接口就变为如下这样
public interface Api {
@FormUrlEncoded @POST("interface?login")
Observable<String> login(@Field("name") String name,@Field("pwd") String pwd);
}
使用如下Transformer
,缺点就是会多了一次Gson
解析
public static <T extends Response> Observable.Transformer<String, T> trans(Class<T> clazz) {
return stringObservable -> stringObservable.map(s -> {
Response response = GsonUtil.parseJson(s, Response.class);
if (null == response || null == response.data) {
throw new RuntimeException("null == response || null == data");
}
if (PatternsUtil.isNum(response.data.toString())) {
throw new RuntimeException(response.data.toString());
}
return GsonUtil.<T>parseJson(s, clazz);
});
}
我们的使用就会变成了如下这样
public void login(View v){
apiservice.login(name,pwd)
.compose(Transformers.switchSchedulers())
.compose(Transformers.<UserModel>trans(UserModel.class))
.subscribe(subscriber);
}
这里也是借鉴而来,主要提供了两种思路,自定义Converter
或者 自定义 Transformer
,如果你有好的想法,愿大家一起交流!