@946898963
2018-05-18T11:51:54.000000Z
字数 6974
阅读 1042
Android控件跟框架
Android源码分析
Network也是一个接口,它只包含一个方法,表示处理网络请求并返回处理结果:
public NetworkResponse performRequest(Request<?> request) throws VolleyError;
Network有一个唯一实现类BasicNetwork。BasicNetwork使用HttpStack执行网络请求,成功后返回一个NetworkResponse,NetworkResponse只是一个简单的记录状态码,body,响应头,服务端是否返回304并且缓存过,执行网络请求时间的类。
首先看下他的构造方法:
/**
* 带一个默认大小的ByteArrayPool缓冲池
* @param httpStack HTTP stack to be used
*/
public BasicNetwork(HttpStack httpStack) {
// If a pool isn't passed in, then build a small default pool that will give us a lot of
// benefit and not use too much memory.
//如果一个池没有通过,将建立一个小的默认缓存池,这样会给我们带来很大的益处,不需要耗费很多内存
this(httpStack, new ByteArrayPool(DEFAULT_POOL_SIZE));
}
/**
* 主构造方法BasicNetwork(HttpStack*,ByteArrayPool*)
* @param httpStack HTTP stack to be used
* @param pool a buffer pool that improves GC performance in copy operations
*/
public BasicNetwork(HttpStack httpStack, ByteArrayPool pool) {
mHttpStack = httpStack;
mPool = pool;
}
有两个参数HttpStack和ByteArrayPool,这两个参数就是主要的成员变量。关于HttpStack和ByteArrayPool,建议阅读:HttpStack及其实现类源码解析&&ByteArrayPool源码解析。
BasicNetwork实现了NetWork接口的performRequest方法,我们来看下这个方法的具体实现:
/**
* @title performRequest执行各种Request请求并以NetworkResponse的形式返回结果
* @param Request
* @return NetworkResponse
* @throws VolleyError
* 定义:{@link Network#performRequest(Request)}
* 被调:{@link NetworkDispatcher#run()}
*
*/
@Override//NetworkDispatcher的run()方法中调用
public NetworkResponse performRequest(Request<?> request) throws VolleyError {
long requestStart = SystemClock.elapsedRealtime();//开始请求时间
while (true) {
HttpResponse httpResponse = null;//apache的请求结果
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);//去调用mHttpStack的实现方法执行请求
StatusLine statusLine = httpResponse.getStatusLine();//获取http状态线
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);
}
//把HttpEntity转化为byte[]数据
responseContents = entityToBytes(httpResponse.getEntity());
// if the request is slow, log it.//如果请求很慢,就打印出来看一下
long requestLifetime = SystemClock.elapsedRealtime() - requestStart;
logSlowRequests(requestLifetime, request, responseContents, statusLine);//打印
//连接正常但是返回无内容,抛出IO异常
if (statusCode != HttpStatus.SC_OK && statusCode != HttpStatus.SC_NO_CONTENT) {
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) {//Bad URL
throw new RuntimeException("Bad URL " + request.getUrl(), e);
} catch (IOException e) {//IO异常
int statusCode = 0;
NetworkResponse networkResponse = null;
if (httpResponse != null) {
statusCode = httpResponse.getStatusLine().getStatusCode();
} else {//如果没有返回httpResponse,就说明没连接
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);//只有状态码为5XX才抛出服务器异常
}
} else {//网络异常
throw new NetworkError(networkResponse);
}
}
}
}
performRequest方法中,使用到了一个while循环,之所以使用while循环,是为了当出错的时候进行重试,关于重试策略,建议阅读:Volley的请求重试策略相关源码分析。看下while循环中的代码:
A. 获取和设置与条件请求相关的首部信息。
Map<String, String> headers = new HashMap<String, String>();//保存缓存数据
addCacheHeaders(headers, request.getCacheEntry());//先获取缓存数据
private void addCacheHeaders(Map<String, String> headers, Cache.Entry entry) {
// If there's no cache entry, we're done.
if (entry == null) {
return;
}
if (entry.etag != null) {
headers.put("If-None-Match", entry.etag);
}
if (entry.lastModified > 0) {
Date refTime = new Date(entry.lastModified);
headers.put("If-Modified-Since", DateUtils.formatDate(refTime));
}
}
从代码中可以看到,如果request.getCacheEntry()不为空,这时候会在设置请求首部的map中添加"If-None-Match"首部和"If-Modified-Since"首部,其值分别为缓存数据的etag和lastModified,"If-None-Match"和"If-Modified-Since"这两个首部是用来进行条件请求的,设置了这两个首部后,发起的请求就是条件请求。
注意在默认的情况下request.getCacheEntry()返回的是null,只有当请求存在缓存数据,但是缓存数据过期的情况下,request.getCacheEntry()才不会为空,具体的实现是在CacheDispatcher的run方法中。在run方法中当获取到本地的缓存,但是本地缓存数据过期的时候,会将本地缓存的数据(首部信息和实体信息)放到Request中,然后将请求放入请求队列中,等待处理。
CacheDispatcher的run方法:
@Override
public void run() {
....
while (true) {
try {
....
Cache.Entry entry = mCache.get(request.getCacheKey());
if (entry == null) {
request.addMarker("cache-miss");
// Cache miss; send off to the network dispatcher.
mNetworkQueue.put(request);
continue;
}
if (entry.isExpired()) {
request.addMarker("cache-hit-expired");
request.setCacheEntry(entry);
mNetworkQueue.put(request);
continue;
}
....
}
}
B. 调用传入的HttpStack的performRequest方法去执行请求,并将响应结果封装成一个HttpResponse。
httpResponse = mHttpStack.performRequest(request,headers);//去调用mHttpStack的实现方法执行请求
C. 获取响应结果的状态码和响应的首部信息,然后根据响应结果的状态码,进行相关的操作。
如果状态码是304,则直接使用本地的缓存数据和响应的首部信息,构造NetworkResponse并返回。
StatusLine statusLine = httpResponse.getStatusLine();//获取http状态线
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);
}
protected static Map<String, String> convertHeaders(Header[] headers) {
Map<String, String> result = new TreeMap<String,String>(String.CASE_INSENSITIVE_ORDER);
for (int i = 0; i < headers.length; i++) {
result.put(headers[i].getName(), headers[i].getValue());
}
return result;
}
如果状态码不是304,说明可能有数据返回,获取响应实体,然后解析响应实体的内容,获得byte[]数组,利用获取到的byte[]数组和响应的首部信息,构造NetworkResponse并返回。
responseContents = entityToBytes(httpResponse.getEntity());
return new NetworkResponse(statusCode, responseContents, responseHeaders, false);
private byte[] entityToBytes(HttpEntity entity) throws IOException, ServerError {
PoolingByteArrayOutputStream bytes = new PoolingByteArrayOutputStream(mPool, (int) entity.getContentLength());
byte[] buffer = null;
try {
InputStream in = entity.getContent();
if (in == null) {
throw new ServerError();
}
buffer = mPool.getBuf(1024);
int count;
while ((count = in.read(buffer)) != -1) {
bytes.write(buffer, 0, count);
}
return bytes.toByteArray();
} finally {
try {
// Close the InputStream and release the resources by "consuming the content".
entity.consumeContent();
} catch (IOException e) {
// This can happen if there was an exception above that left the entity in
// an invalid state.
VolleyLog.v("Error occured when calling consumingContent");
}
mPool.returnBuf(buffer);
bytes.close();
}
}
这里用到了PoolingByteArrayOutputStream,关于PoolingByteArrayOutputStream,建议阅读:PoolingByteArrayOutputStream源码解析。
D. 当出现异常的时候,进行相关的操作,这里主要关心Volley的重试策略,建议阅读:Volley的请求重试策略相关源码分析。
参考链接: