通过Volley我们能学到什么?(2) — 刨析网络请求框架
来源:互联网 发布:java面向对象练习题 编辑:程序博客网 时间:2024/06/05 06:01
接上一章来讲网络请求的大体过程,Volley是如何封装并使用HttpURLConnection和HttpClient的。
目录
网络请求的基本逻辑
网络请求的交互层—>BasicNetwork
封装HttpURLConnection实现网络连接
RequestQueue.java
从通过Volley我们能学到什么?(1) — 工作原理与设计模式的NetworkDispatcher.java中的调用网络请求开始讲起。。
NetworkResponse networkResponse = mNetwork.performRequest(request);
Volley中网络请求一共分为三层,大体结构如下:
1、NetworkDispatcher获取Request对象并分发给BasicNetwork;
2、BasicNetwork得到Request对象后,配置头文件等配置信息分发给HttpStack;
3、HttpStack得到Request对象和配置信息后进行真正的网络请求;
4、HttpStack将网络请求的结果返回给BasicNetwork;
5、BasicNetwork得到返回结果,如果成功则返回给NetworkDispatcher,否则处理其他异常情况;
第一层NetworkDispatcher已讲完,这篇主要讲第二层(BasicNetwork)和第三层(HttpStack)。
网络请求的交互层—>BasicNetwork
BasicNetwork.java
这一行代码直接调用的是BasicNetwork.java中的performRequest()方法
public NetworkResponse performRequest(Request<?> request) throws VolleyError { long requestStart = SystemClock.elapsedRealtime(); while (true) { HttpResponse httpResponse = null; byte[] responseContents = null; Map<String, String> responseHeaders = Collections.emptyMap(); try { // Gather headers. Map<String, String> headers = new HashMap<String, String>(); addCacheHeaders(headers, request.getCacheEntry()); httpResponse = mHttpStack.performRequest(request, headers); StatusLine statusLine = httpResponse.getStatusLine(); int statusCode = statusLine.getStatusCode(); responseHeaders = convertHeaders(httpResponse.getAllHeaders()); // Handle cache validation. if (statusCode == HttpStatus.SC_NOT_MODIFIED) { Entry entry = request.getCacheEntry(); if (entry == null) { return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED, null, responseHeaders, true, SystemClock.elapsedRealtime() - requestStart); } // A HTTP 304 response does not have all header fields. We // have to use the header fields from the cache entry plus // the new ones from the response. // http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.5 entry.responseHeaders.putAll(responseHeaders); return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED, entry.data, entry.responseHeaders, true, SystemClock.elapsedRealtime() - requestStart); } // Some responses such as 204s do not have content. We must check. if (httpResponse.getEntity() != null) { responseContents = entityToBytes(httpResponse.getEntity()); } else { // Add 0 byte response as a way of honestly representing a // no-content request. responseContents = new byte[0]; } // if the request is slow, log it. long requestLifetime = SystemClock.elapsedRealtime() - requestStart; logSlowRequests(requestLifetime, request, responseContents, statusLine); if (statusCode < 200 || statusCode > 299) { throw new IOException(); } return new NetworkResponse(statusCode, responseContents, responseHeaders, false, SystemClock.elapsedRealtime() - requestStart); } catch (SocketTimeoutException e) { attemptRetryOnException("socket", request, new TimeoutError()); } catch (ConnectTimeoutException e) { attemptRetryOnException("connection", request, new TimeoutError()); } catch (MalformedURLException e) { throw new RuntimeException("Bad URL " + request.getUrl(), e); } catch (IOException e) { int statusCode = 0; NetworkResponse networkResponse = null; if (httpResponse != null) { statusCode = httpResponse.getStatusLine().getStatusCode(); } else { throw new NoConnectionError(e); } VolleyLog.e("Unexpected response code %d for %s", statusCode, request.getUrl()); if (responseContents != null) { networkResponse = new NetworkResponse(statusCode, responseContents, responseHeaders, false, SystemClock.elapsedRealtime() - requestStart); if (statusCode == HttpStatus.SC_UNAUTHORIZED || statusCode == HttpStatus.SC_FORBIDDEN) { attemptRetryOnException("auth", request, new AuthFailureError(networkResponse)); } else { // TODO: Only throw ServerError for 5xx status codes. throw new ServerError(networkResponse); } } else { throw new NetworkError(networkResponse); } } } }
1、首先创建循环机制,使请求失败可以再次请求(3行);
2、添加头部信息(9 - 10行);
3、调用HttpStack对象进行网络请求,进入网络请求的第三层(11行);
4、获取请求结果的状态(12 - 13行);
5、更新头部信息(14行);
6、如果获取的状态行是304则说明之前已获取过数据且服务器未做修改,直接返回上次请求的数据(16 - 32行);
7、将数据内容写入到responseContents里(35 - 41行);
8、请求完成,如果访问总时长超过3秒将访问的详细信息打印出来(44 - 45行);
9、如果状态码返回是异常,报IO异常,跳转到下面的catch中(47 - 49);
10、如果是连接异常则重新连接(53、55行);
11、如果超时,则跳出循环向上抛异常,超时时间最大值可设置(56行);
12、处理IO异常,如果是因为访问无权限或禁止访问这种认证问题,可以再给一次机会,否则直接抛异常(59 - 80行);
多次网络请求机制
BasicNetwork.java
接下来我们来看一下Volley多次访问逻辑,入口为attemptRetryOnException()方法。
private static void attemptRetryOnException(String logPrefix, Request<?> request, VolleyError exception) throws VolleyError { RetryPolicy retryPolicy = request.getRetryPolicy(); int oldTimeout = request.getTimeoutMs(); try { retryPolicy.retry(exception); } catch (VolleyError e) { request.addMarker( String.format("%s-timeout-giveup [timeout=%s]", logPrefix, oldTimeout)); throw e; } request.addMarker(String.format("%s-retry [timeout=%s]", logPrefix, oldTimeout)); }
1、获取Request对象里面的RetryPolicy对象,并获取超时时间(3 - 4行);
2、调用RetryPolicy对象的retry()方法来检测是否需要重新访问(7行);
向下看retry()的源码
DefaultRetryPolicy.java
public void retry(VolleyError error) throws VolleyError { mCurrentRetryCount++; mCurrentTimeoutMs += (mCurrentTimeoutMs * mBackoffMultiplier); if (!hasAttemptRemaining()) { throw error; } }
1、重新访问次数加一(2行);
2、累加超时时间(3行);
3、判断重新访问次数是否大于最大访问次数(默认是1,可自定义),大于最大值报异常跳出循环(4行);
封装HttpURLConnection实现网络连接(HttpClient暂不整理)
如果是Android2.3即以上版本调用上面HttpStack对象的performRequest()方法的会映射到HurlStack类里面的performRequest()方法来实现网络连接。
HurlStack.java
public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders) throws IOException, AuthFailureError { String url = request.getUrl(); HashMap<String, String> map = new HashMap<String, String>(); map.putAll(request.getHeaders()); map.putAll(additionalHeaders); if (mUrlRewriter != null) { String rewritten = mUrlRewriter.rewriteUrl(url); if (rewritten == null) { throw new IOException("URL blocked by rewriter: " + url); } url = rewritten; } URL parsedUrl = new URL(url); HttpURLConnection connection = openConnection(parsedUrl, request); for (String headerName : map.keySet()) { connection.addRequestProperty(headerName, map.get(headerName)); } setConnectionParametersForRequest(connection, request); // Initialize HttpResponse with data from the HttpURLConnection. ProtocolVersion protocolVersion = new ProtocolVersion("HTTP", 1, 1); int responseCode = 0; try { responseCode = connection.getResponseCode(); } catch (IOException e) { connection.getErrorStream(); responseCode = connection.getResponseCode(); } if (responseCode == -1) { // -1 is returned by getResponseCode() if the response code could not be retrieved. // Signal to the caller that something was wrong with the connection. throw new IOException("Could not retrieve response code from HttpUrlConnection."); } StatusLine responseStatus = new BasicStatusLine(protocolVersion, connection.getResponseCode(), connection.getResponseMessage()); BasicHttpResponse response = new BasicHttpResponse(responseStatus); response.setEntity(entityFromConnection(connection)); for (Entry<String, List<String>> header : connection.getHeaderFields().entrySet()) { if (header.getKey() != null) { Header h = new BasicHeader(header.getKey(), header.getValue().get(0)); response.addHeader(h); } } return response;
1、得到URL并获取头部信息(3 - 6行);
2、mUrlRewriter是干什么的?mUrlRewriter默认为null,但如果赋值的话,所有使用到的网络请求URL统一替换成mUrlRewriter中的URL,应该是项目测试用的(7 - 13行);
3、创建HttpURLConnection对象,并做一些连接前的配置,看一下这个方法的细节(15行);
调用createConnection()方法创建一个HttpURLConnection对象,createConnection()方法里面只是判断了一下是不是通过https访问。如果是https则在HttpsURLConnection这个类里面的两个静态对象初始化,
如果是http的话不做处理。因为如果是http的话后面的执行直接用connection这个引用就可以,如果是https的话由于已经在HttpsURLConnection这个类中把必要的静态数据初始化了所以可以直接将connection强行转换(170行、179 - 181行);
4、设置头部(16 - 18行);
5、设置连接参数,支持8种请求方式(19行);
6、获取连接最终状态,如果是-1说明不能获取到,向上抛异常(22 - 34行);
7、配置BasicHttpResponse对象以便在最后返回它(35 - 37行);
8、将body写入到BasicHttpResponse对象中(38行);
9、将头部信息写入到BasicHttpResponse对象中(39 - 44行);
这样整体的网络结构就差不多了。如果继续深入可以研究上传功能的源码和HttpUrlConnect的源码。
1 0
- 通过Volley我们能学到什么?(2) — 刨析网络请求框架
- 通过Volley我们能学到什么?(3) — 缓存原理
- 通过Volley我们能学到什么?(1) — 工作原理与设计模式
- 从HelloWorld中我们能学到什么
- 网络请求框架---Volley
- Volley网络请求框架
- 网络请求框架---Volley
- 网络请求框架-Volley
- Volley-----网络请求框架
- Volley网络请求框架
- Volley网络请求框架
- Volley网络请求框架
- Android —— 网络请求框架 Volley
- Volley网络请求框架简析——Android网络请求框架(三)
- Java百问之一——从java HelloWorld中我们能学到什么?
- 大学里我们能从老师那里学到什么
- 我们能从java的HelloWorld学到什么?
- 我们能从java的HelloWorld学到什么?
- hibernate映射(三)——一对一
- 统计ip,进行合并输出
- Android UI---View与ViewGroup
- Android中Shape、selector在xml中的使用、切换按钮的背景图案
- 使用OpenH323开发
- 通过Volley我们能学到什么?(2) — 刨析网络请求框架
- Git入门基础 - CSDN学院视频
- jsp取出session的几种方式
- java 对List集合进行排序
- 素数判断和素数筛法
- linux命令
- GBK,UTF-8,和ISO8859-1编码区别与get,post请求中文乱码处理
- 在Fragment中我想点击按钮然后关闭当前的Fragment返回上一个Fragment该如何实现。
- Java快速排序