在平时最普通的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()); 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()); T t = JsonUtils.fromJson(resultString, type); requestListener.onSuccess(t); ``` 通过封装好的 JsonUtils将String转化为对应的model类型,我们知道json转实体对象的时候,需要指明其类type,那这里的type是如何获取到的呢?
其中getTType ()的具体实现为: ```java public static Type getTType(Class<?> clazz) { Type[] types = clazz.getGenericInterfaces(); clazz.getInterfaces(); if (types.length > 0) { 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同样适用于其他类似的网络请求框架
小弟不才,如有问题,欢迎指出。