上一篇Android 网络请求框架总结(一)总结了一些我在Android网络请求解析这一块的一些经验,过程是循序渐进的,从无到有,从不完善到完善,这一篇将继续优化以上的代码,看看还有哪些需要做的,地址,参数,回调,网络判断,请求状态判断,json解析,错误信息收集都有了,看似没有什么问题,还是结合实际的问题来分析,在很早的一个项目中我发现了一个问题,而且是在网络状态很差,我快速切换页面的时候才会出现,症状大概是这样,进去一个页面,发出了网络请求,我耐心的等待数据的加载完成,再出去另一个页面去请求另一个数据,根本就加载不出来,退出应用出去再进就好了,当时的网络请求框架是当时公司的技术总监写的,我大概看了下源码,就简单的封装了一个异步任务(AsyncTask),发现了请求是不能取消的,那就意味着当页面销毁的时候请求并没有取消,才导致的我上面描述的bug,继续优化代码
public class HttpClient {
public static RequestQueue queue = Volley.newRequestQueue(App.getContext());
public static final String RESULT_CODE = "code"; //状态码,后台返回成功或者失败
public static final String RETURN_MESSAGE = "message";//消息,后台返回的文本消息,提示或者错误信息
public static final String RESULT = "result";//成功的返回结果
public static final String SUCCESS = "1"; //成功
public static final String FAILURE = "0";//失败
public static void postRequest(Context context, String url, final Map map, final OnResponseListener listener) {
StringRequest request = new StringRequest(Request.Method.POST, url, new Response.Listener() {
@Override
public void onResponse(String response) {
try {
JSONObject jsonObject = new JSONObject(response);//将json数据转化为json对象
if (!jsonObject.isNull(RESULT_CODE)) {//判断code字段是否存在
String code = jsonObject.getString(RESULT_CODE);//活得code的值
if (code.equals(SUCCESS)) { //成功则继续往下判断
if (!jsonObject.isNull(RESULT)) {
String result = jsonObject.getString(RESULT);
listener.success(result);
}
} else if (code.equals(FAILURE)) {//失败返回错误信息
if (!jsonObject.isNull(RETURN_MESSAGE)) {//判断message字段是否存在
listener.failure(jsonObject.getString(RETURN_MESSAGE));//返回后台失败信息
}
} else {
listener.failure("无效的状态码");//返回状态码无效的错误信息
}
} else {
listener.failure("状态码不存在");//返回状态码不存在的错误信息
}
} catch (JSONException e) {
e.printStackTrace();
listener.failure(e.getLocalizedMessage());//返回json异常的错误信息
}
listener.success(response);
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
listener.failure(error.getLocalizedMessage());//返回Volley异常的错误信息
}
}) {
@Override
protected Map getParams() throws AuthFailureError {
return map;
}
};
//判断网络是否连接
if (NetworkUtils.isConnectedByState(App.getContext())) {
addRequest(request, context);//将请求添加到队列
} else {
listener.failure("网络未连接");//返回网络未连接的错误信息
}
}
/**
* 添加请求到请求队列中
*
* @param request 请求
* @param tag 目标对象,Activity或者Fragment
*/
private static void addRequest(Request> request, Object tag) {
if (tag != null) {
request.setTag(tag);
}
queue.add(request);
}
/**
* 取消目标对象中的所有请求
*
* @param tag 目标对象,Activity或者Fragment
*/
public static void cancelRequest(Object tag) {
queue.cancelAll(tag);
}
使用
/**
* Activity销毁的时候取消该Activity的所有请求
*/
@Override
protected void onDestroy() {
super.onDestroy();
HttpClient.cancelRequest(this);
}
/**
* Fragment 视图销毁的时候取消该Fragment的所有网络请求
*/
@Override
public void onDestroyView() {
super.onDestroyView();
HttpClient.cancelRequest(this);
}
Map map = new HashMap<>();
map.put("key1","value1");
map.put("key2", "value1");
HttpClient.postRequest(this,"http://www.baidu.com", map, new OnResponseListener() {
@Override
public void success(String result) {
System.out.println("result = " + result);
//这里我新建了一个测试的对象,采用了gson来将json数据转换为bean对象
//解析成对象,嵌套的对象也是可以的
TestBean testBean = new Gson().fromJson(result, TestBean.class);
//解析成list
Type type = new TypeToken>() {
}.getType();
List testBeans = new Gson().fromJson(result, type);
//解析成数组
TestBean[] testBeans1 = new Gson().fromJson(result, TestBean[].class);
//这个时候想转化为list可以调用下面的方法
List testBeans2 = Arrays.asList(testBeans1);
}
@Override
public void failure(String errorMessage) {
System.out.println("errorMessage = " + errorMessage);
}
});
继续走,看看这个框架还可以做哪些事情,上一篇讲了关于gson解析相关的内容,注释比较详细,应该可以满足基本的需求,问题就是每次都要手动解析,使用起来还是显得有些麻烦,可以在框架中自动解析Json数,使用的时候直接拿到对象操作就行了,我们尝试下
先改一下接口
public interface OnResponseListener {
void success(Object result);
void failure(String errorMessage);
}
HttpClient.java
public class HttpClient {
public static RequestQueue queue = Volley.newRequestQueue(App.getContext());
public static final String RESULT_CODE = "code"; //状态码,后台返回成功或者失败
public static final String RETURN_MESSAGE = "message";//消息,后台返回的文本消息,提示或者错误信息
public static final String RESULT = "result";//成功的返回结果
public static final String SUCCESS = "1"; //成功
public static final String FAILURE = "0";//失败
public static void postRequest(Context context, String url, final Class clazz, final Map map, final OnResponseListener listener) {
StringRequest request = new StringRequest(Request.Method.POST, url, new Response.Listener() {
@Override
public void onResponse(String response) {
try {
JSONObject jsonObject = new JSONObject(response);//将json数据转化为json对象
if (!jsonObject.isNull(RESULT_CODE)) {//判断code字段是否存在
String code = jsonObject.getString(RESULT_CODE);//活得code的值
if (code.equals(SUCCESS)) { //成功则继续往下判断
if (!jsonObject.isNull(RESULT)) {
String result = jsonObject.getString(RESULT);
Object o;
if (result.charAt(0) == '{') {
//解析对象
o = new Gson().fromJson(result, clazz);
} else {
//这个方法是在stackoverflow中找到的可将json转换为list,普通的通过type去解析是不行的
o = new Gson().fromJson(result, com.google.gson.internal.$Gson$Types.newParameterizedTypeWithOwner(null, ArrayList.class, clazz));
}
listener.success(o);
}
} else if (code.equals(FAILURE)) {//失败返回错误信息
if (!jsonObject.isNull(RETURN_MESSAGE)) {//判断message字段是否存在
listener.failure(jsonObject.getString(RETURN_MESSAGE));//返回后台失败信息
}
} else {
listener.failure("无效的状态码");//返回状态码无效的错误信息
}
} else {
listener.failure("状态码不存在");//返回状态码不存在的错误信息
}
} catch (JSONException e) {
e.printStackTrace();
listener.failure(e.getLocalizedMessage());//返回json异常的错误信息
}
listener.success(response);
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
listener.failure(error.getLocalizedMessage());//返回Volley异常的错误信息
}
}) {
@Override
protected Map getParams() throws AuthFailureError {
return map;
}
};
//判断网络是否连接
if (NetworkUtils.isConnectedByState(App.getContext())) {
addRequest(request, context);//将请求添加到队列
} else {
listener.failure("网络未连接");//返回网络未连接的错误信息
}
}
/**
* 添加请求到请求队列中
*
* @param request 请求
* @param tag 目标对象,Activity或者Fragment
*/
private static void addRequest(Request> request, Object tag) {
if (tag != null) {
request.setTag(tag);
}
queue.add(request);
}
/**
* 取消目标对象中的所有请求,在Activity或者Fragment销毁的时候调用
*
* @param tag 目标对象,Activity或者Fragment
*/
public static void cancelRequest(Object tag) {
queue.cancelAll(tag);
}
使用
HttpClient.postRequest(this, "http://www.baidu.com", TestBean.class, map, new OnResponseListener() {
@Override
public void success(Object result) {
//如果result为对象
TestBean testBean = ((TestBean) result);
//如果result为list
List testBeans = (ArrayList) result;
}
@Override
public void failure(String errorMessage) {
System.out.println("errorMessage = " + errorMessage);
}
});
这样就完成了自动解析json的过程,调用的时候强转一下对象的类型就行了
重新封装的框架的好处还有很多,可以打印每次请求和响应的数据,批量处理空值,还可以在这里进行数据缓存,包括后期的一些扩展都很方便