一.源码解析
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);
}