Retrofit实战之json反序列化的那些事

来源:互联网 发布:最新淘宝我是卖家在哪 编辑:程序博客网 时间:2024/06/05 15:35

Retrofit实战之json反序列化的那些事


retrofit是一个十分优秀的网络框架,它为了我们封装了很多内容,使我们请求十分方便,获取也十分轻松,对于返回的json可以轻松的用gson自动解析。但是在这个方便的后面,也带来了一些小小的隐患。

下面就有两种情况,在json被反序列化时,给我们在这个炎热的夏天里造成了蛋蛋的凉意。

接口请求失败,可它还是要全部反序列化

一般来说接口返回的形式包括:返回码,信息,返回数据这三部分,大致如下:

{    statusCode: "200",    statusMessage: "回传成功",    data: {       //内容    }}

而网络请求时,也会创建一个Response范型类,作为请求结果的映射。

public class Response <T>{    private int statusCode;    private String statusMessage;    private T data;    public int getStatusCode() {        return statusCode;    }    public void setStatusCode(int statusCode) {        this.statusCode = statusCode;    }    public String getStatusMessage() {        return statusMessage;    }    public void setStatusMessage(String statusMessage) {        this.statusMessage = statusMessage;    }    public T getData() {        return data;    }    public void setData(T data) {        this.data = data;    }}

当接口请求失败或者返回的数据错误(也就是返回码是错误码时),按照常理,我们是不会解析data的。可gson每次都会对json进行反序列化,不管json里面的数据是否是成功的,里面的data都会被反序列化。这个就有些忧伤了,我们不是应该只对成功的请求才反序列化json里面的data数据吗?

接口返回数据形式不一致

我司的接口就有这个蛋疼的问题,失败时统一返回的格式是下面这种:

{    statusCode: "103",    statusMessage: "请求失败",    data: []

只要请求失败,不管data里面的数据是JSONObject 还是JSONArray,都返回JSONArray。这就蛋疼了,经常会有json解析的异常抛出,于是我不得不含泪解决。

解决方法

基于上面的2个需求,我们得找出解决方法。由于我用retrofit都是用gson解析,所以解决这个问题的方法用的是gson特性。然后再思考一下问题的本质,其实就是它在不该反序列化的地方反序列化,导致了出错。所以我们只要找到自定义反序列化的方法就行了。

我相信很多人都用过gson,但是你真的了解它吗,其实它是很强大的,是吧,皮卡丘。对于gson不熟悉的,可以看看下面文章 你真的会用Gson吗?Gson使用指南。

一般gson进行对象化映射都有两个步骤,第一步,getTypeAdapter(),第二步,read()反序列化。这在retrofit的GsonResponseBodyConverter源码中清晰可见:

  //为了方便观看,我对代码进行了一些修改public T convert(ResponseBody value) throws IOException {    TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));    JsonReader jsonReader = gson.newJsonReader(value.charStream());    try {      return adapter.read(jsonReader);    } finally {      value.close();    }  }}

对于TypeAdapter我们是可以自定义的,由于这里我们只需要反序列化,所以我们只用实现JsonDeserializer,并指定需要处理的类型就可以了,具体代码如下。

public class ResultJsonDeser implements JsonDeserializer<Response<?>> {    @Override    public Response<?> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {        Response response = new Response();        if (json.isJsonObject()){            JsonObject jsonObject = json.getAsJsonObject();            int code = jsonObject.get("statusCode").getAsInt();            response.setStatusCode(code);            response.setStatusMessage(jsonObject.get("statusMessage").getAsString());            if (code != 200){                return response;            }            Type itemType = ((ParameterizedType) typeOfT).getActualTypeArguments()[0];            response.setData(context.deserialize(jsonObject.get("data"), itemType));            return response;        }        return response;    }}

最后将ResultJsonDeser在gson中注册,我们就可以愉快的玩耍,不用担心那些格式的问题了。

Gson gson = new GsonBuilder()                .registerTypeHierarchyAdapter(Response.class, new ResultJsonDeser())                .setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")                .create();

当然,最后的最后,还是需要将gson加入retrofit中的,addConverterFactory(GsonConverterFactory.create(gson))。相信大家,对于这类问题都有一些思路了,对于retrofit的使用也能更加得劲了。

0 0
原创粉丝点击