前言
本文主要是对在项目中处理json的实际应用。
直接上代码
解析数据的时候有可能会遇到同字段不同数据类型的问题,以下面数据为例:
// 返回成功的数据
{
"retMsg": "success",
"retData": {
"city": "杭州",
"phone": "13282191888",
"prefix": "1328219",
"province": "浙江",
"supplier": "联通"
},
"errNum": 0
}
// 返回失败的数据
{
"errNum": -1,
"retMsg": "[132821918888]\u6b64\u53f7\u7801\u4e0d\u662f\u5408\u6cd5\u7684\u624b\u673a\u53f7!",
"retData": []
}
从返回的数据可以看出retData的类型变成了两种(对象和数组),如果只定义成对象当返回失败的时候GSON无法解析并抛出异常。因为我这里GSON是组合Retrofit使用的,当解析失败异常会回调到Subscriber中的以下方法里:
public void onError(Throwable e) {}
在这个onError方法里,我们无法获取到其它有用的数据。比如说我们想获取错误信息提示给用户,但在这里是没有办法的。
- 解决这个问题的方法有两种:
- 使用反序列化解析数据
- 把数据通过异常抛出,并做处理
- 反序列化有一些局限性,这里的retMsg定义的是未知的泛型并不能很好的解决。所以以下的方法我使用抛出异常数据。
一、初始化Retrofit时使用自定义拦截器。
Retrofit mAdapter = new Retrofit.Builder()
.baseUrl(SERVER)
// 增加自定义解析
.addConverterFactory(GsonDConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.client(getBuilder().build())
.build();
二、自定义responseBody对返回的数据解析。
public final class GsonDConverterFactory extends Converter.Factory {
public static GsonDConverterFactory create() {
return create(new Gson());
}
public static GsonDConverterFactory create(Gson gson) {
return new GsonDConverterFactory(gson);
}
private final Gson gson;
private GsonDConverterFactory(Gson gson) {
if (gson == null) throw new NullPointerException("gson == null");
this.gson = gson;
}
@Override public Converter < ResponseBody,
?>responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
return new GsonResponseBodyConverter < >(gson, type);
}
@Override public Converter < ?,
RequestBody > requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
TypeAdapter < ?>adapter = gson.getAdapter(TypeToken.get(type));
return new GsonRequestBodyConverter < >(gson, adapter);
}
}
三、根据code值选择不同的类解析数据。
在convert方法里,先不指定具体泛型解析出返回的数据。通过code值判断本次请求:成功就返回type类型的解析数据,失败就使用我们提前定义好的HttpErrResult对象进行解析,并通过ResultException把错误信息返回回去。
final class GsonResponseBodyConverter < T > implements Converter < ResponseBody,
T > {
private final Gson gson;
private final Type type;
GsonResponseBodyConverter(Gson gson, Type type) {
this.gson = gson;
this.type = type;
}
/**
* 针对数据返回成功、错误不同类型字段处理
*/
@Override public T convert(ResponseBody value) throws IOException {
String response = value.string();
try {
// 这里的type实际类型是 HttpResult PhoneBean就是retData要获取的对象。
HttpResult result = gson.fromJson(response, HttpResult.class);
int code = result.getErrNum();
if (code == 0) {
return gson.fromJson(response, type);
} else {
Log.d("HttpManager", "返回err==:" + response);
HttpErrResult errResponse = gson.fromJson(response, HttpErrResult.class);
if (code == -1) {
throw new ResultException(errResponse.getRetMsg(), code);
} else {
throw new ResultException(errResponse.getErrMsg(), code);
}
}
} finally {
value.close();
}
}
}
四、自定义Retrofit的Subscriber方法解析失败与成功信息。
我们之前的异常会回调到onError方法里,通过判断是否是ResultException异常,取出异常信息回调给Presenter处理。
public abstract class HttpResultCallBack < M > extends Subscriber < HttpResult < M >> {
/**
* 请求返回
*/
public abstract void onResponse(M m, int status);
public abstract void onErr(String msg, int status);
/**
* 请求完成
*/
@Override public void onCompleted() {}
@Override public void onError(Throwable e) {
if (e != null) {
if (e instanceof ResultException) {
ResultException err = (ResultException) e;
onErr(err.getErrMsg(), GlobalVar.RESULT_UNLOGIN);
} else {
onErr("网络异常,请检查网络", GlobalVar.RESULT_UNLOGIN);
Log.d("HttpManager", "解析失败==:" + e.getMessage());
}
}
onCompleted();
}
/**
* Http请求失败
*/
private void onHttpFail(String msg, int status) {
onErr(msg, status);
}
@Override public void onNext(HttpResult < M > result) {
String jsonResponse = new Gson().toJson(result);
Log.d("HttpManager", "返回ok==:" + jsonResponse);
if (result.getErrNum() == GlobalVar.RESULT_OK) {
onResponse(result.getRetData(), GlobalVar.RESULT_OK);
} else {
onHttpFail(result.getErrMsg(), GlobalVar.RESULT_UNLOGIN);
}
}
}
github源码下载