前一篇《Android网络框架volley学习(六)调度器CacheDispatcher简析》了解了关于缓存线程调度CacheDispatcher的工作原理,它里面会判断缓存是否存在、是否过期以及是否需要刷新等操作,如果不满足的话则需要加入到网络请求队列,从而让NetworkDispatcher去处理它。本篇我们继续来学习NetworkDispatcher实现过程,看看网络线程是如何处理请求的?
NetworkDispatcher
同样的,我们首先了解一下它的内部成员变量。
/** 请求队列 */
private final BlockingQueue<Request<?>> mQueue;
/** 执行网络请求的接口 */
private final Network mNetwork;
/** 缓存类接口 */
private final Cache mCache;
/** 结果分发 */
private final ResponseDelivery mDelivery;
接着我们看下它的初始化过程,也就是构造函数。
public NetworkDispatcher(BlockingQueue<Request<?>> queue,
Network network, Cache cache, ResponseDelivery delivery) {
mQueue = queue;
mNetwork = network;
mCache = cache;
mDelivery = delivery;
}
很简单,从前面我们得知,NetworkDispatcher其实也是一个线程,那么我们来看下它的run方法。
@Override
public void run() {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
while (true) {
try {
processRequest();
} catch (InterruptedException e) {
// We may have been interrupted because it was time to quit.
if (mQuit) {
return;
}
}
}
}
跟CacheDispatcher一样的逻辑,接着查看processRequest方法内部实现细节,由于这个方法实现过程代码比较长,我们一步一步进行分析。
Request<?> request = mQueue.take();
if (request.isCanceled()) {
request.finish("network-discard-cancelled");
request.notifyListenerResponseNotUsable();
return;
}
同样的,首先从网络请求队列中取出一条请求,判断它是否取消了,接着往下看。
// Perform the network request.
NetworkResponse networkResponse = mNetwork.performRequest(request);
执行了网络请求,然后解析网络请求结果到response
//判断是否是304(表示资源没有修改过)
if (networkResponse.notModified && request.hasHadResponseDelivered()) {
request.finish("not-modified");
request.notifyListenerResponseNotUsable();
return;
}
// Parse the response here on the worker thread.
Response<?> response = request.parseNetworkResponse(networkResponse);
request.addMarker("network-parse-complete");
接下来就比较重要了
if (request.shouldCache() && response.cacheEntry != null) {
mCache.put(request.getCacheKey(), response.cacheEntry);
request.addMarker("network-cache-written");
}
// Post the response back.
request.markDelivered();
mDelivery.postResponse(request, response);
request.notifyListenerResponseReceived(response);
首先判断这个请求结果是否应该缓存,同时分发这个网络请求结果出去。到这里NetworkDispatcher都讲完了,但是,是不是一脸懵逼?讲的啥?里面还有很多东西没有讲到,我们接着分析。
执行网络请求
上面有行代码时执行网络请求的,
NetworkResponse networkResponse = mNetwork.performRequest(request);
具体是如何实现这个请求的呢?通过performRequest,它是
public interface Network {
NetworkResponse performRequest(Request<?> request) throws VolleyError;
}
它是一个接口,我们需要知道它的实现类,我们通过查看volley的源码可以知道,它的实现类是BasicNetwork,接下来我们分析一下它的实现过程。
纵观的源码,我们可以看到其中有个成员变量
/**
* @deprecated Should never have been exposed in the API. This field may be removed in a future
* release of Volley.
*/
@Deprecated
protected final HttpStack mHttpStack;
其实,HttpStack mHttpStack是实际的网络请求类,进去可以看到它是一个接口,它的实现类有两个
- HttpClientStack,基于Apache的HttpClient请求方式
- HurlStack,基于Java的HttpURLConnection请求方式
从《Android网络框架volley学习(三)底层网络请求分析》我们可以了解到网络请求方式有两种,根据api是否大于9来判断使用哪种方式。
我们接着分析performRequest方法,
httpResponse = mBaseHttpStack.executeRequest(request, additionalRequestHeaders);
int statusCode = httpResponse.getStatusCode();
responseHeaders = httpResponse.getHeaders();
// 首先判断请求资源是否被修改过
if (statusCode == HttpURLConnection.HTTP_NOT_MODIFIED) {
Entry entry = request.getCacheEntry();
if (entry == null) {
return new NetworkResponse(HttpURLConnection.HTTP_NOT_MODIFIED, null, true,
SystemClock.elapsedRealtime() - requestStart, responseHeaders);
}
// Combine cached and response headers so the response will be complete.
List<Header> combinedHeaders = combineHeaders(responseHeaders, entry);
return new NetworkResponse(HttpURLConnection.HTTP_NOT_MODIFIED, entry.data,
true, SystemClock.elapsedRealtime() - requestStart, combinedHeaders);
}
首先判断请求的内容是否被修改过,如果没有被修改过,再根据缓存中是否存在该结果,包装返回NetworkResponse。如果已经修改过的话,则获取请求结果,再次包装返回请求结果。
// Some responses such as 204s do not have content. We must check.
InputStream inputStream = httpResponse.getContent();
if (inputStream != null) {
responseContents =
inputStreamToBytes(inputStream, httpResponse.getContentLength());
} 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, statusCode);
if (statusCode < 200 || statusCode > 299) {
throw new IOException();
}
return new NetworkResponse(statusCode, responseContents, false,
SystemClock.elapsedRealtime() - requestStart, responseHeaders);
如果期间出错的话,则需要根据code来进行分别处理,包括
int statusCode;
if (httpResponse != null) {
statusCode = httpResponse.getStatusCode();
} else {
//网络有问题
throw new NoConnectionError(e);
}
VolleyLog.e("Unexpected response code %d for %s", statusCode, request.getUrl());
NetworkResponse networkResponse;
if (responseContents != null) {
networkResponse = new NetworkResponse(statusCode, responseContents, false,
SystemClock.elapsedRealtime() - requestStart, responseHeaders);
if (statusCode == HttpURLConnection.HTTP_UNAUTHORIZED ||
statusCode == HttpURLConnection.HTTP_FORBIDDEN) {
attemptRetryOnException("auth",
request, new AuthFailureError(networkResponse));
} else if (statusCode >= 400 && statusCode <= 499) {
// Don't retry other client errors.
throw new ClientError(networkResponse);
} else if (statusCode >= 500 && statusCode <= 599) {
if (request.shouldRetryServerErrors()) {
attemptRetryOnException("server",
request, new ServerError(networkResponse));
} else {
throw new ServerError(networkResponse);
}
} else {
// 3xx? No reason to retry.
throw new ServerError(networkResponse);
}
} else {
attemptRetryOnException("network", request, new NetworkError());
}
- 如果根本就没有响应内容httpResponse==null,说明网络连接有问题(也就是说手机没有联网),自己抛出异常结束
- 302,301错误,说明资源被重定向,做简单的记录
- 401,403错误,身份验证错误,重试
- 302,301错误,重试
回顾一下,总结流程。
图片来自于Volley 源码解析