Android实现Rxjava2+Retrofit完美封装( 二 )

三.通过GsonConverterFactory获取真实响应数据
在第一节中我们构建了服务器响应数据BasicResponse,BasicResponse由code、message、和content三个字段 。其中code为服务器返回的错误码 。我们会事先和服务器约定成功时的code值,比如200表示请求成功 。但通常在请求服务器数据过程中免不了会出现各种错误 。例如用户登录时密码错误、请求参数错误的情况 。此时服务器会根据错误情况返回对应的错误码 。一般来说,我们只关心成功时即code为200时的content数据 。而对于code不为200时我们只需要给出对应的Toast提示即可 。事实上我们对我们有用的仅仅时code为200时的content数据 。因此我们可以考虑过滤掉code和message,在请求成功的回调中只返回content的内容 。
在此种情况下就需要我们通过自定义GsonConverterFactory来实现了 。我们可以直接从Retrofit的源码中copy出GsonConverterFactory的三个相关类来做修改 。
其中最终要的一部分是修改GsonResponseBodyConverter中的convert方法 。在该方法中拿到服务器响应数据并判断code是否为200 。如果是,则获取到content并返回,如果不是,则在此处可以抛出对应的自定义的异常 。然后再Observer中统一处理异常情况 。GsonResponseBodyConverter代码如下:
final class GsonResponseBodyConverter<T> implements Converter<ResponseBody, Object> { private final TypeAdapter<T> adapter; GsonResponseBodyConverter(TypeAdapter<T> adapter) { this.adapter = adapter; } @Override public Object convert(ResponseBody value) throws IOException { try { BasicResponse response = (BasicResponse) adapter.fromJson(value.charStream()); if (response.getCode()==200) { return response.getResults(); } else { // 特定 API 的错误,在相应的 DefaultObserver 的 onError 的方法中进行处理 throw new ServerResponseException(response.getCode(), response.getMessage()); } } finally { value.close(); } return null; }}四.构建DefaultObserver处理服务器响应 。
上一节中我们讲到了在请求服务器时可能出现的一些例如密码错误、参数错误的情况,服务器给我们返回了对应的错误码,我们根据错误码抛出了对应自定义异常 。除此之外在我们发起网络请求时还可能发生一些异常情况 。例如没有网络、请求超时或者服务器返回了数据但在解析时出现了数据解析异常等 。对于这样的情况我们也要进行统一处理的 。那么我们就需要自定义一个DefaultObserver类继承Observer,并重写相应的方法 。
该类中最重要的两个方法时onNext和onError 。
1.在服务器返回数据成功的情况下会回调到onNext方法 。因此我们可以在DefaultObserver中定义一个抽象方法onSuccess(T response),在调用网络时重写onSuccess方法即可 。
2.如果在请求服务器过程中出现任何异常,都会回调到onError方法中 。包括上节中我们自己抛出的异常都会回调到onError 。因此我们的重头戏就是处理onError 。在onError中我们根据异常信息给出对应的Toast提示即可 。
DefaultObserver类的代码如下:
public abstract class DefaultObserver<T> implements Observer<T> { @Override public void onSubscribe(Disposable d) { } @Override public void onNext(T response) { onSuccess(response); onFinish(); } @Override public void onError(Throwable e) { LogUtils.e("Retrofit", e.getMessage()); if (e instanceof HttpException) { // HTTP错误 onException(ExceptionReason.BAD_NETWORK); } else if (e instanceof ConnectException || e instanceof UnknownHostException) { // 连接错误 onException(ExceptionReason.CONNECT_ERROR); } else if (e instanceof InterruptedIOException) { // 连接超时 onException(ExceptionReason.CONNECT_TIMEOUT); } else if (e instanceof JsonParseException || e instanceof JSONException || e instanceof ParseException) { // 解析错误 onException(ExceptionReason.PARSE_ERROR); }else if(e instanceof ServerResponseException){ onFail(e.getMessage()); } else { onException(ExceptionReason.UNKNOWN_ERROR); } onFinish(); } @Override public void onComplete() { } /** * 请求成功 * * @param response 服务器返回的数据 */ abstract public void onSuccess(T response); /** * 服务器返回数据,但响应码不为200 * */ public void onFail(String message) { ToastUtils.show(message); } public void onFinish(){} /** * 请求异常 * * @param reason */ public void onException(ExceptionReason reason) { switch (reason) { case CONNECT_ERROR: ToastUtils.show(R.string.connect_error, Toast.LENGTH_SHORT); break; case CONNECT_TIMEOUT: ToastUtils.show(R.string.connect_timeout, Toast.LENGTH_SHORT); break; case BAD_NETWORK: ToastUtils.show(R.string.bad_network, Toast.LENGTH_SHORT); break; case PARSE_ERROR: ToastUtils.show(R.string.parse_error, Toast.LENGTH_SHORT); break; case UNKNOWN_ERROR: default: ToastUtils.show(R.string.unknown_error, Toast.LENGTH_SHORT); break; } } /** * 请求网络失败原因 */ public enum ExceptionReason { /** * 解析数据失败 */ PARSE_ERROR, /** * 网络问题 */ BAD_NETWORK, /** * 连接错误 */ CONNECT_ERROR, /** * 连接超时 */ CONNECT_TIMEOUT, /** * 未知错误 */ UNKNOWN_ERROR, }}


推荐阅读