一、网络请求
移动软件及APP实现主要在于本地功能交互的实现与数据的展示,且数据常为移动软件的核心。数据常源自于
服务器,网络数据交互则扮演十分重要的角色。
二、网络情形考量
网络请求在数据交互中扮演重要角色。因其流程的特殊性,存有多种情形需要考虑。
1,返回值情形
接口崩溃,返回异常情形;以及接口正确抛出异常的返回
接口返回内容为空,或者状态正常,可用数据部分为空;
接口正常返回数据,解析数据出现错误;
2,网络请求执行过程
执行开始前:提示网络请求正在执行,给予用户良好的反馈,屏蔽用户的其他操作【管控恶意点击,重复提交】
执行过程中:网络请求在特定条件下(返回,Home,黑屏,强制关机,电话、短信的插入),需要对网络请求做暂停、取消、重新开始等处理;
执行完成后:解析数据,重新渲染界面;尤其是网络请求错误时,需要数据的回显与数据的重置,并给与用户友好的提示。
针对上面情形,需要考虑的是:
(1)限定网络请求头,可以避免重复提交,也能实现接口的版本控制;
(2)网络请求最好实现队列效果,能够在合适的时间处理其中的某一个网络请求;
(3)实现线程池管理,不能无限开启线程,管控当前应用对系统的消耗;
(4)实现网络请求的数据压缩与加密,增强网络请求的安全性,减少数据量,增强信息传送、携带能力。
网络请求主要交互数据类型:
一般是字符串与图片文件的交互。随应用的扩展,扩展到表单、Map数据,文件以及数据流。
三、开源框架
现已经公开使用且使用效果较为良好的网络请求方式主要有:HttpClient、HttpURLConnection、AsyncTask、xUtlis、Volley、OkHttp、Retrofit、Android_Async_Http。从最初始的网络情求到应用框架实现封装。挑选实现进行管控。
HttpURLConnection:
public class NetWorkHttpConnection { /** * 超时时间 */ private static final int TIMEOUT_IN_MILLIONS = 5000; /** * HttpURLConnection GET请求 * 访问路径中直接拼接完整参数 * * @param urlStr 访问路径 * @return 返回内容 */ public static String doGet(String urlStr) { URL url = null; HttpURLConnection conn = null; InputStream is = null; ByteArrayOutputStream baos = null; try { url = new URL(urlStr); conn = (HttpURLConnection) url.openConnection(); conn.setReadTimeout(TIMEOUT_IN_MILLIONS); conn.setConnectTimeout(TIMEOUT_IN_MILLIONS); conn.setRequestMethod("GET"); conn.setRequestProperty("accept", "*/*"); conn.setRequestProperty("connection", "Keep-Alive"); conn.setRequestProperty("Content-type", "application/json"); if (conn.getResponseCode() == 200) { is = conn.getInputStream(); baos = new ByteArrayOutputStream(); int len = -1; byte[] buf = new byte[128]; while ((len = is.read(buf)) != -1) { baos.write(buf, 0, len); } baos.flush(); return baos.toString(); } else { throw new RuntimeException(" responseCode is not 200 ... "); } } catch (Exception e) { e.printStackTrace(); } finally { try { if (is != null) is.close(); } catch (IOException e) { e.printStackTrace(); } try { if (baos != null) baos.close(); } catch (IOException e) { e.printStackTrace(); } if (conn != null) { conn.disconnect(); } } return null; } /** * HttpURLConnection POST请求 * * @param url 发送请求的 URL * @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。 * @return 所代表远程资源的响应结果 */ public static String doPost(String url, String param) { PrintWriter out = null; BufferedReader in = null; String result = ""; try { URL realUrl = new URL(url); // 打开和URL之间的连接 HttpURLConnection conn = (HttpURLConnection) realUrl .openConnection(); // 设置通用的请求属性 conn.setRequestProperty("accept", "*/*"); conn.setRequestProperty("connection", "Keep-Alive"); conn.setRequestMethod("POST"); conn.setRequestProperty("Content-Type", "application/json"); conn.setRequestProperty("charset", "utf-8"); conn.setUseCaches(false); // 发送POST请求必须设置如下两行 conn.setDoOutput(true); conn.setDoInput(true); conn.setReadTimeout(TIMEOUT_IN_MILLIONS); conn.setConnectTimeout(TIMEOUT_IN_MILLIONS); if (param != null && !param.trim().equals("")) { // 获取URLConnection对象对应的输出流 out = new PrintWriter(conn.getOutputStream()); // 发送请求参数 out.print(param); // flush输出流的缓冲 out.flush(); } // 定义BufferedReader输入流来读取URL的响应 in = new BufferedReader(new InputStreamReader(conn.getInputStream())); String line; while ((line = in.readLine()) != null) { result += line; } } catch (Exception e) { e.printStackTrace(); } // 使用finally块来关闭输出流、输入流 finally { try { if (out != null) { out.close(); } if (in != null) { in.close(); } } catch (IOException ex) { ex.printStackTrace(); } } return result; } }Volley:
** * 使用Volley封装网络请求 * GET/POST都可以,在外部调用时传参一致 * * @version V1.0 * @author: Vision * @date: 2016-06-22 13:38 */ public class NetWorkVolley { public static RequestQueue mQueue = Volley.newRequestQueue(DemoApplicatipn.getApplication()); /** * POST方法访问网络 * * @param method 访问路径 * @param params 传递参数 * @param listener 正确返回值监听器 * @param errorListener 错误时监听器 */ public static void netWorkByPost(String method, JSONObject params, Response.Listener<JSONObject> listener, Response.ErrorListener errorListener) { JsonObjectRequest request = null; request = new JsonObjectRequest(Request.Method.POST, method, params, listener, errorListener) { @Override public Map<String, String> getHeaders() throws AuthFailureError { HashMap<String, String> headers = new HashMap<String, String>(); headers.put("User-Agent", "有代表意义的String串"); headers.put("content-type", "x-www-form-urlencoded"); headers.put("Accept-Encoding", "gzip"); headers.put("api-version", 1 + ""); return headers; } }; request.setRetryPolicy(new DefaultRetryPolicy(15000,//设置默认超时时间,15秒 DefaultRetryPolicy.DEFAULT_MAX_RETRIES,//默认最大尝试次数 1 DefaultRetryPolicy.DEFAULT_BACKOFF_MULT)); mQueue.add(request); } /** * GET方法实现网络请求 * * @param url 访问路径 * @param parames 传递参数 * @param listener 正确返回值监听器 * @param errorListener 错误时监听器 */ public static void netWorkByGet(String url, Map<String, Object> parames, Response.Listener<JSONObject> listener, Response.ErrorListener errorListener) { /** * 拼接参数 */ String paramStr = ""; if (parames != null) { for (String key : parames.keySet()) { paramStr = paramStr + key + "=" + parames.get(key).toString() + "&"; } url = url + "?" + paramStr; } /** * 执行网络请求 */ JsonObjectRequest request = new JsonObjectRequest(Request.Method.GET, url, null, listener, errorListener) { @Override public Map<String, String> getHeaders() throws AuthFailureError { HashMap<String, String> headers = new HashMap<String, String>(); headers.put("User-Agent", "有代表意义的String串"); headers.put("content-type", "x-www-form-urlencoded"); headers.put("Accept-Encoding", "gzip"); headers.put("api-version", 1 + ""); return headers; } }; request.setRetryPolicy(new DefaultRetryPolicy(15000,//设置默认超时时间,15秒 0,//默认最大尝试次数 1.0f)); mQueue.add(request); } }xUtlis:
/** * @version V1.0 * @author: Vision * @date: 2016-06-22 14:33 */ public class NetWorkXUtils { /** * xutil请求网络数据POST * * @param url * @param map * @param requestCallBack */ public static void getJsonPostForXutil(String url, Map<String, Object> map, RequestCallBack<String> requestCallBack) { HttpUtils httpUtils = new HttpUtils(); httpUtils.configTimeout(10000); httpUtils.configSoTimeout(10000); httpUtils.configCurrentHttpCacheExpiry(1000); RequestParams params = new RequestParams(); for (Map.Entry<String, Object> entry : map.entrySet()) { params.addBodyParameter(entry.getKey(), entry.getValue().toString()); } httpUtils.send(HttpRequest.HttpMethod.POST, url, params, requestCallBack); } /** * xutils请求网络数据GET * * @param url * @param map * @param requestCallBack */ public static void getJsonGetForXutil(String url, Map<String, Object> map, RequestCallBack<String> requestCallBack) { HttpUtils httpUtils = new HttpUtils(); String getUrl = ""; if (map != null) { for (Map.Entry<String, Object> entry : map.entrySet()) { getUrl = getUrl + entry.getKey() + "=" + entry.getValue() + "&"; } if (getUrl.length() > 1) { getUrl.substring(0, getUrl.length() - 1); } } httpUtils.configCurrentHttpCacheExpiry(1000);//防止连续点击的网络请求 httpUtils.send(HttpRequest.HttpMethod.GET, url + getUrl, requestCallBack); } }Gzip实现类,调用GzipNetWork实现网络请求【数据压缩】
public class GZipRequest extends StringRequest { /** * 使用当前构造方法,没有参数体,不能使用POST请求 * 要使用post,需要重写获取参数方法 getParams() * * @param method * @param url * @param listener * @param errorListener */ public GZipRequest(int method, String url, Response.Listener<String> listener, Response.ErrorListener errorListener) { super(method, url, listener, errorListener); } /** * 默认Get请求 * * @param url * @param listener * @param errorListener */ public GZipRequest(String url, Response.Listener<String> listener, Response.ErrorListener errorListener) { super(url, listener, errorListener); } // parse the gzip response using a GZIPInputStream @Override protected Response<String> parseNetworkResponse(NetworkResponse response) { /** * 先判断数据是否为Gzip * 【使用gzip模式访问数据,不压缩的数据格式不接受】 * * Content-Encoding 数据返回格式是否压缩的关键判断字段 */ Map<String, String> headers = response.headers; if (headers != null && headers.containsKey("Content-Encoding") && headers.get("Content-Encoding").contains("gzip")) { String output = ""; // note: better to use StringBuilder try { final GZIPInputStream gStream = new GZIPInputStream(new ByteArrayInputStream(response.data)); final InputStreamReader reader = new InputStreamReader(gStream); final BufferedReader in = new BufferedReader(reader); String read; while ((read = in.readLine()) != null) { output += read; } reader.close(); in.close(); gStream.close(); } catch (IOException e) { return Response.error(new ParseError()); } return Response.success(output, HttpHeaderParser.parseCacheHeaders(response)); } else { String output = null; try { output = new String(response.data, "utf-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } return Response.success(output, HttpHeaderParser.parseCacheHeaders(response)); } } @Override public Map<String, String> getHeaders() throws AuthFailureError { HashMap<String, String> headers = new HashMap<String, String>(); headers.put("User-Agent", "有意义的String"); headers.put("content-type", "application/x-www-form-urlencoded"); headers.put("Accept-Encoding", "gzip"); return headers; } }
public class GzipNetWork { public static RequestQueue mQueue = Volley.newRequestQueue(DemoApplicatipn.getApplication()); /** * 使用Gzip的GET网络请求 * * @param url 网络请求不带参数的链接地址 * @param params 网络请求参数 * @param listener 网络请求正确返回值监听器 * @param errorListener 网络请求错误返回值监听器 */ public static void netGzipWorkByGet(String url, Map<String, String> params, Response.Listener<String> listener, Response.ErrorListener errorListener) { String paramStr = ""; if (params != null) { for (String key : params.keySet()) { paramStr = paramStr + key + "=" + params.get(key) + "&"; } url = url + "?" + paramStr; } GZipRequest gZipRequest = new GZipRequest(url, listener, errorListener); mQueue.add(gZipRequest); } /** * 使用Gzip的POST网络请求 * * @param url 网络请求不带参数的链接地址 * @param params 网络请求参数 * @param listener 网络请求正确返回值监听器 * @param errorListener 网络请求错误返回值监听器 */ public static void netGzipWorkByPost(String url, final Map<String, String> params, Response.Listener<String> listener, Response.ErrorListener errorListener) { GZipRequest gZipRequest = new GZipRequest(Request.Method.POST, url, listener, errorListener) { @Override protected Map<String, String> getParams() throws AuthFailureError { return params; } }; mQueue.add(gZipRequest); } }在实际使用均调用NetWork类中的方法就可以,GET/POST方法都已实现,调用参数形式一致。主要是GET实现在链接后直接拼接参数,能够从外部看到,不安全且传输数据量有限;POST请求有自己的请求体,不在链接中展示,安全性较高,且数据内容长度没有限制。
四、相互关系
HttpURLConnection的实现中,传参较为麻烦,只是基本功能的实现,也没有效率方面的考虑;
xUtlis特长在于四大模块:Dbutlis/ViewUtlis/HttpUtlis/BitmapUtlis。
Volley实现队列访问,是一个相对比较成熟的框架。
Volley+Gzip则实现了网络数据的压缩。
Android基础学习【历史流程重走】 ---- 网络请求(四)
原文:http://blog.csdn.net/u013205623/article/details/51734922