Retrofit实战之json反序列化的那些事
2016-07-22 16:30
441 查看
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的使用也能更加得劲了。
相关文章推荐
- android wifi 无线调试
- jackson、Gson反序列化 泛型
- 使用 Python 处理 JSON 格式的数据
- Gson.toJson()时内存溢出StackOverflowError
- XML 与 JSON 优劣对比
- 虚拟化基础架构Windows 2008篇之10-使用WDS安装Windows 7
- VBA将excel数据表生成JSON文件
- 拨号网络的简单知识
- 菜鸟必看网络名词
- 通晓网络测试常用命令
- 网络路由技术及运用2
- IP网络路由技术
- 网络防火墙的设置技巧
- 网络管理之IP地址篇
- 网络路由技术及运用3
- 网络路由技术及运用4
- 网络路由技术及运用1
- 无线局域网络简介一
- 无线局域网络简介二