android json解析异常,json数据解析异常而导致网络请求失败的解决办法(其一)

问题概述

笔者在开发过程中临时遇到一个本来仅有web端的项目临时增加Android端,导致后端在出接口时并未考虑Android端的json数据的解析,导致接口是这样的。。。。

正确请求

{

"code": 0,

"data": {

"user": {

"id": 145,

"name": "abtion",

"school_id": 1,

"sex": "男",

"add_on": null,

"status": 1,

"role": "student",

"created_at": "2017-08-05 18:26:31",

"updated_at": "2017-08-19 12:41:50"

}

}

}

错误请求

{

"code": 20002,

"data": "Password Wrong"

}

这也就是说在请求正确时服务端返回的数据中data是在java中的一个对象,而错误时却变成了String,这就导致了错误的请求在解析json时抛出异常导致请求失败,而且抛出的异常是无法拿到错误码和错误信息的。

问题分析

我们该如何解决这个问题呢,经过思考,方法有三:

呼叫可爱的后端老哥改接口,将错误信息改由message字段输出

给okhttp添加拦截器,在retrofit解析json前解析json数据并存储。

自定义Gson响应体变换器和响应变换工厂,在请求错误时抛出异常并保存错误码和错误信息。

由于该项目已经上线,再改接口无异于痴人说梦,因加拦截器的效率也不及第三种方法日后再分享,本次采用自定义Gson响应体变换器和响应变换工厂的方法来解决。

具体解决办法

1、切入点

首先请看一张图片

d6bd6bd5fce3

我们通常情况下跟图中一样采用的是Gosn工厂变换器,而本次抛出异常的地方就是这个变换器,自定义工厂变换器就可以完美解决我们的问题。

2、自定义Gson响应体变换器

class GsonResponseBodyConverter implements Converter {

private final Gson gson;

private final Type type;

public GsonResponseBodyConverter(Gson gson, Type type) {

this.gson = gson;

this.type = type;

}

@Override

public T convert(ResponseBody value) throws IOException {

//将返回的json数据储存在String类型的response中

String response = value.string();

//将外层的数据解析到APIResponse类型的httpResult中

APIResponse httpResult = gson.fromJson(response,APIResponse.class);

//服务端设定0为正确的请求,故在此为判断标准

if (httpResult.getCode()==0){

//直接解析,正确请求不会导致json解析异常

return gson.fromJson(response,type);

}else {

//定义错误响应体,并通过抛出自定义异常传递错误码及错误信息

ErrorResponse errorResponse = gson.fromJson(response,ErrorResponse.class);

throw new ResultException(errorResponse.getCode(),errorResponse.getData());

}

}

}

附上APIResponse类,ErrorResponse类和ResultException类

public class APIResponse extends BaseModel {

private int code = -2;

private T data;

public int getCode() {

return code;

}

public void setCode(int code) {

this.code = code;

}

public T getData() {

return data;

}

public void setData(T data) {

this.data = data;

}

}

public class ErrorResponse {

private int code;

private String data;

public ErrorResponse(int code, String data) {

this.code = code;

this.data = data;

}

public int getCode() {

return code;

}

public void setCode(int code) {

this.code = code;

}

public String getData() {

return data;

}

public void setData(String data) {

this.data = data;

}

}

public class ResultException extends IOException {

private int code;

private String msg;

public ResultException(int code, String msg) {

this.code = code;

this.msg = msg;

}

public int getCode() {

return code;

}

public void setCode(int code) {

this.code = code;

}

public String getMsg() {

return msg;

}

public void setMsg(String msg) {

this.msg = msg;

}

}

3、自定义响应变换工厂

class ResponseConverterFactory extends Converter.Factory {

public static ResponseConverterFactory create() {

return create(new Gson());

}

public static ResponseConverterFactory create(Gson gson) {

return new ResponseConverterFactory(gson);

}

private final Gson gson;

private ResponseConverterFactory(Gson gson) {

if (gson == null) throw new NullPointerException("gson == null");

this.gson = gson;

}

@Override

public Converter responseBodyConverter(Type type, java.lang.annotation.Annotation[] annotations, Retrofit retrofit) {

return new GsonResponseBodyConverter<>(gson,type);

}

@Override

public Converter, RequestBody> requestBodyConverter(Type type, java.lang.annotation.Annotation[] parameterAnnotations, java.lang.annotation.Annotation[] methodAnnotations, Retrofit retrofit) {

TypeAdapter> adapter = gson.getAdapter(TypeToken.get(type));

return new GsonRequestBodyConverter<>(gson, adapter);

}

}

4、调用自定义的响应变换工厂

在构造Retrofit时在addConverterFactory()方法中传入ResponseConverterFactory.create()就可以了。

/**

* 构造Retrofit

*

* @return retrofit

*/

private static Retrofit getRetrofit() {

if (retrofit == null) {

retrofit = new Retrofit.Builder()

.baseUrl(Config.APP_SERVER_BASE_URL)

.addConverterFactory(ResponseConverterFactory.create())

.client(getClient())

.build();

}

return retrofit;

}

5、在网络请求的onFailure中接收异常信息并进行处理

@Override

public void onFailure(Call> call, Throwable t) {

if (t instanceof ResultException) {

ToastUtil.showToast(((ResultException) t).getMsg(), ((ResultException) t).getCode());

} else {

ToastUtil.showToast("网络请求失败,请稍后再试");

}

}

到这里就完成了,别忘了Gson的请求体变换器是default限定的。改改限定符就好了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值