Android(安卓)网络请求框架总结(二)
16lz
2021-01-25
上一篇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<String, String> map, final OnResponseListener listener) { StringRequest request = new StringRequest(Request.Method.POST, url, new Response.Listener<String>() { @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<String, String> 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<String,String> 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<ArrayList<TestBean>>() { }.getType(); List<TestBean> testBeans = new Gson().fromJson(result, type); //解析成数组 TestBean[] testBeans1 = new Gson().fromJson(result, TestBean[].class); //这个时候想转化为list可以调用下面的方法 List<TestBean> 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<String, String> map, final OnResponseListener listener) { StringRequest request = new StringRequest(Request.Method.POST, url, new Response.Listener<String>() { @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<String, String> 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<TestBean> testBeans = (ArrayList<TestBean>) result; } @Override public void failure(String errorMessage) { System.out.println("errorMessage = " + errorMessage); } });
这样就完成了自动解析json的过程,调用的时候强转一下对象的类型就行了
重新封装的框架的好处还有很多,可以打印每次请求和响应的数据,批量处理空值,还可以在这里进行数据缓存,包括后期的一些扩展都很方便
更多相关文章
- Nginx系列教程(六)| 手把手教你搭建 LNMP 架构并部署天空网络电影
- 使用android真机测试http网络连接异常解决办法
- Android之socket
- Handler ThreadHandler Looper的总结
- Android中activity和xml的第一个项目
- Android中将xml布局文件转化为View树的过程分析(上)
- Android常见面试题&字节跳动、阿里、腾讯2019实习生Android岗部
- [置顶] Android(安卓)Binder跨进程与非跨进程的传输异同源码分析
- 重温String和StringBuffer