在平时最普通的Volley的网络请求中,我们StringRequest是这样请求网络数据的:
StringRequest stringRequest = new StringRequest("http://www.baidu.com",
new Response.Listener<String>() {
@Override
public void onResponse(String response) {
Log.d("TAG", response);
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.e("TAG", error.getMessage(), error);
}
注意在onResponse的时候是拿到的string类型,拿到string后对其再进行相关的解析,我们是否是可以对其直接封装然后拿到具体想要类型的model数据结构呢?所以对其网络请求架构进行一次封装,到达如下效果:
GetGoodDetailByGidRequest getGoodDetailByGidRequest = new GetGoodDetailByGidRequest(mCouponId,
new RequestListener<List<CouponModel>>() {
@Override
public void onSuccess(List<CouponModel> result) {
}
@Override
public void onError(Exception e) {
e.printStackTrace();
stopLoadingDialog();
}
});
这里我们在构造Request的时候指定了返回数据的类型,这样的话就方便了我们在写业务的时候直接使用解析好的数据结构,具体如何做到的呢?
一、让每个Request基于一个带有范型请求类
public abstract class BaseApiRequest<T>
这里的T就是目标请求期望的model类
在具体实现的时候继承基类,并指定返回类型,下面是一个例子:
public class GetGoodDetailByGidRequest extends BaseApiRequest<List<CouponModel>> {
public static final String url = CURL.GoodDetailURL;
public GetGoodDetailByGidRequest(String goodId, RequestListener<List<CouponModel>> requestListener) {
super(requestListener);
this.mUrlParams.put("id", goodId);
}
@Override
public String getBaseUrl() {
return url;
}
}
二、在基类中构造网络请求
protected StringRequest getStringRequest() {
return new StringRequest(requestMethod, getRequestUrl(),
response -> parseJson(response),
error -> requestListener.onError(error)) {
@Override
protected Map<String, String> getParams() {
return mEntityParams;
}
};
}
在此处实现可以看到Request在基类中进行,然后分别处理返回结果
三、对返回结果进行解析
private void parseJson(String response) {
int responseCode = 0;
int errorCode = 400;
try {
JSONObject jsonObject = new JSONObject(response);
String resultString = jsonObject.getString("data");
if (jsonObject.has("code")) {
responseCode = jsonObject.getInt("code");
}
if (jsonObject.has("error")) {
errorCode = jsonObject.getInt("error");
}
if (responseCode == 200 || errorCode == 0) {
if (!TextUtils.isEmpty(response)) {
Type type = getTType(requestListener.getClass());
//泛型是实体或者List等类型
T t = JsonUtils.fromJson(resultString, type);
requestListener.onSuccess(t);
return;
}
ToastUtils.showToast("Data is empty!");
}
ToastUtils.showToast("Response code is error.");
requestListener.onError(new ParseError());
} catch (JSONException e) {
ToastUtils.showToast(e.toString());
e.printStackTrace();
}
}
这里是最关键的一步,由于和后端约定好相关返回字段,那么只需要解析字段中目标model的数据,其中比较重要的是这段代码
Type type = getTType(requestListener.getClass());
//泛型是实体或者List等类型
T t = JsonUtils.fromJson(resultString, type);
requestListener.onSuccess(t);
通过封装好的 JsonUtils将String转化为对应的model类型,我们知道json转实体对象的时候,需要指明其类type,那这里的type是如何获取到的呢?
其中getTType ()的具体实现为:
public static Type getTType(Class<?> clazz) {
//以Type的形式返回本类直接实现的接口.
Type[] types = clazz.getGenericInterfaces();
clazz.getInterfaces();
if (types.length > 0) {
//返回表示此类型实际类型参数的 Type 对象的数组
Type[] interfacesTypes = ((ParameterizedType) types[0]).getActualTypeArguments();
return interfacesTypes[0];
}
return null;
}
通过次方法能够获取到请求实现中所指明的请求类型,其中getGenericInterfaces等相关原理可以阅读:https://my.oschina.net/617669559/blog/3012228
所以对于
public class GetGoodDetailByGidRequest extends BaseApiRequest<List<CouponModel>>
那么获取到的就是List类型
四、通过Listener回调相关解析结果
拿到解析好的result并回调给构造Request方法中的listener使用
T t = JsonUtils.fromJson(resultString, type);
requestListener.onSuccess(t);
这样对整个网络请求后的返回数据直接进行解析方便多了。
总结:
1、本文最主要是对基本Request类进行改造,以达到不需要每次重复写解析返回的String数据
2、在获取目标的类的类型的时候,主要是去获取基类中的“T”类型
3、设计不仅适用用Volley同样适用于其他类似的网络请求框架
小弟不才,如有问题,欢迎指出。