在平时最普通的Volley的网络请求中,我们StringRequest是这样请求网络数据的:

1
2
3
4
5
6
7
8
9
10
11
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数据结构呢?所以对其网络请求架构进行一次封装,到达如下效果:

1
2
3
4
5
6
7
8
9
10
11
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基于一个带有范型请求类

1
public abstract class BaseApiRequest<T>  

这里的T就是目标请求期望的model类
在具体实现的时候继承基类,并指定返回类型,下面是一个例子:

1
2
3
4
5
6
7
8
9
10
11
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;
}
}

二、在基类中构造网络请求

1
2
3
4
5
6
7
8
9
10
protected StringRequest getStringRequest() {
return new StringRequest(requestMethod, getRequestUrl(),
response -> parseJson(response),
error -> requestListener.onError(error)) {
@Override
protected Map<String, String> getParams() {
return mEntityParams;
}
};
}

在此处实现可以看到Request在基类中进行,然后分别处理返回结果

三、对返回结果进行解析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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的数据,其中比较重要的是这段代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
	Type type = getTType(requestListener.getClass());
//泛型是实体或者List等类型
T t = JsonUtils.fromJson(resultString, type);
requestListener.onSuccess(t);
```
通过封装好的 JsonUtils将String转化为对应的model类型,我们知道json转实体对象的时候,需要指明其类type,那这里的type是如何获取到的呢?

其中getTType ()的具体实现为:
```java
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

所以对于

1
public class GetGoodDetailByGidRequest extends BaseApiRequest<List<CouponModel>>

那么获取到的就是List类型

四、通过Listener回调相关解析结果

拿到解析好的result并回调给构造Request方法中的listener使用

1
2
T t = JsonUtils.fromJson(resultString, type);
requestListener.onSuccess(t);

这样对整个网络请求后的返回数据直接进行解析方便多了。

总结:

1、本文最主要是对基本Request类进行改造,以达到不需要每次重复写解析返回的String数据

2、在获取目标的类的类型的时候,主要是去获取基类中的“T”类型

3、设计不仅适用用Volley同样适用于其他类似的网络请求框架

小弟不才,如有问题,欢迎指出。