Volley源码学习(二):网络请求处理,HurlStack类,BasicNetwork类,ByteArrayPool,PoolingByteArrayOutputStream
2016-03-14 20:50
483 查看
一.源码解析
volley用于处理网络请求的HurlStack类和BasicNetwork类,继承HttpStack接口
1.接口HttpStack,定义了方法HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders),处理网络请求,获得HttpResponse。
2.类HurlStack:使用httpconnection处理网络请求
主要方法:方法:performRequest(Request<?> request, Map<String, String> additionalHeaders)
逻辑流程:获得url,new map添加request里的headers和additionalHeaders→有mUrlRewriter就重写url→获得connection = openConnection(parsedUrl, request);→遍历map,connection.addRequestProperty,为connection添加headers.→获得responseCode并new
responseStatus→response = new BasicHttpResponse(responseStatus);→response.setEntity,设置entity→遍历,将connection的headers添加到response里,最后返回。
方法:setConnectionParametersForRequest(HttpURLConnection connection,Request<?> request)
根据request,为connection设置method,post,get,delete,put等
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 = 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; }
3.类BaseNetwork
主要方法方法:addCacheHeaders(Map<String, String> headers, Cache.Entry entry),如果存在Cache.Entry,headers.put("If-Modified-Since", DateUtils.formatDate(refTime));
方法:NetworkResponse performRequest(Request<?> request):包装HurlStack类的方法,增加一些其他操作。
调用addCacheHeaders方法,为request增加CacheHeaders→调用hurlStack的performRequest方法获得httpResponse→获得statusLine,获得statusCode
→如果StatusCode==304,则直接返回NetworkResponse,将NetWorkResponse的notModified设为true→对于204等没有content的状态码,再确认一次,将
httpResponse的entity转换到responseContents里→状态码为200-299时,返回NetworkResponse,但notModified为false.→不是时,抛出IOException
→在catch里根据responseContent是否为null,进行对应处理,抛出异常。
方法:entityToBytes(HttpEntity entity),将entity转换为byte[],利用到PoolingByteArrayOutputStream类,ByteArrayPool类,之前ByteArrayPool类是一个持有
不同长度的byte[]的pool,可以提供大于目标size的byte[],防止不同size的byte[]重复创建,提供性能。PoolingByteArrayOutputStream则是利用ByteArrayPool
提供的byte[]的输出流。
public NetworkResponse performRequest(Request<?> request) throws VolleyError { long requestStart = SystemClock.elapsedRealtime(); while (true) { HttpResponse httpResponse = null; byte[] responseContents = null; Map<String, String> responseHeaders = new HashMap<String, String>(); 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) { return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED, request.getCacheEntry().data, responseHeaders, true); } // 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); } 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); 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); } } } }
3.类NetworkResponse
NetworkResponse(int statusCode, byte[] data, Map<String, String> headers,boolean notModified)构造方法就可以看出用途包装后,如果server返回304,notModified就是true说明在指定时间未修改,直接从本地cache获取。
4.类ByteArrayPool,提供不同size的byte[],提高性能
getBuf(int len),trim(),returnBuf(byte[] buf)3个主要方法。public class ByteArrayPool
mBuffersByLastUse = new LinkedList<byte[]>(); //用于将最近使用的byte[]添加到末尾,删除byte[]时,删除头部的,即删除最久不用的
private List<byte[]> mBuffersBySize = new ArrayList<byte[]>(64); //按大小顺序排列的list<pre name="code" class="html">public synchronized void returnBuf(byte[] buf) { //将buf添加到pool里
if (buf == null || buf.length > mSizeLimit) { return; } mBuffersByLastUse.add(buf); //添加到末尾,表明最近使用的 int pos = Collections.binarySearch(mBuffersBySize, buf, BUF_COMPARATOR); //使用二分法将buf插入到mBufferBysize里 if (pos < 0) { pos = -pos - 1; } mBuffersBySize.add(pos, buf); mCurrentSize += buf.length; trim(); //添加后,确认是否超出limitSize,超出就删除旧的byte[] }<pre name="code" class="html"> private synchronized void trim() { while (mCurrentSize > mSizeLimit) { byte[] buf = mBuffersByLastUse.remove(0); //找到eldest的byte[] mBuffersBySize.remove(buf); //删除 mCurrentSize -= buf.length; } }
public synchronized byte[] getBuf(int len) { //根据len获得大于该len的byte[] for (int i = 0; i < mBuffersBySize.size(); i++) { byte[] buf = mBuffersBySize.get(i); if (buf.length >= len) { mCurrentSize -= buf.length; mBuffersBySize.remove(i); //移除buf mBuffersByLastUse.remove(buf); return buf; } } return new byte[len]; }
5.类PoolingByteArrayOutputStream,使用ByteArrayPool的ByteArrayOutputStream,提供性能
private void expand(int i) { //扩展读取时用的buf /* Can the buffer handle @i more bytes, if not expand it */ if (count + i <= buf.length) { return; } byte[] newbuf = mPool.getBuf((count + i) * 2); //从mPool里获得byte[],size至少是原来的2倍 System.arraycopy(buf, 0, newbuf, 0, count); mPool.returnBuf(buf); //将不用的buf return到pool里保存 buf = newbuf; //buf指向newbuf }</span><pre name="code" class="html"> public synchronized void write(byte[] buffer, int offset, int len) { expand(len); //写时调用expand方法,检查是否需要扩展, super.write(buffer, offset, len); }
@Override public void close() throws IOException { //关闭,或回收时都将buf 还回pool mPool.returnBuf(buf); buf = null; super.close(); } @Override public void finalize() { mPool.returnBuf(buf); }
相关文章推荐
- 网络编程_TCP_Socket通信_聊天室_私聊_构思_实现JAVA193-194
- 关于Eclipse使用OkHttp
- HTTP协议状态码详解
- 深入分析 Java 中的中文编码问题 (文章来自网络)
- 网络编程TCP总结及实践-C语言
- tcp简单传输过程分析
- C#成魔之路<14> 网络编程技术(2 )System.Net.Sockets命名空间
- HTTP 错误 404.3 – Not Found 由于扩展配置问题而无法提供您请求的页面。如果该页面是脚本,请添加处理程序。如果应下载文件,请添加 MIME 映射。
- 使用Reachability网络监测
- 0915-多线程 网络开始
- 黑马程序员-Java网络编程
- Linux常用网络命令
- com.android.volley 里面网络请求的使用
- Android统计网络流量
- 网络编程之僵尸进程
- okhttp 的使用
- HttpClient的get请求
- TCP/IP学习笔记(1)
- 神经网络大总结
- 网络请求