Retrofit+RxJava错误预处理

概述

在使用 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);

}

Transformer 和 Func 处理的区别

如上的处理,我们定义了 一个 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,如果你有好的想法,愿大家一起交流!

你可能感兴趣的:(错误处理,retrofit,rxjava)