public void start() {
stop();
mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery);
mCacheDispatcher.start();
for (int i = 0; i < mDispatchers.length; i++) {
NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork,
mCache, mDelivery);
mDispatchers[i] = networkDispatcher;
networkDispatcher.star
t();
}
}
public void stop() {
if (mCacheDispatcher != null) {
mCacheDispatcher.quit();
}
for (final NetworkDispatcher mDispatcher : mDispatchers) {
if (mDispatcher != null) {
mDispatcher.quit();
}
}
}
先调用 stop() 方法将当前正在进行 Dispatcher 都停掉,然后创建了一个 CacheDispatcher 实例,并调用了它的 start() 方法,接着在一个循环里去创建 NetworkDispatcher 的实例,分别调用它们的 start() 方法,这里的 CacheDispatcher 和 NetworkDispatcher 都是继承自 Thread 的,默认情况下 for 循环会执行四次,也就是说当调用了 Volley.newRequestQueue(context) 之后,就会有五个线程在后台运行,等待网络请求的到来,其中 CacheDispatcher 是缓存线程,NetworkDispatcher 是网络请求线程。
得到 RequestQueue 之后,构建相应的 Request,然后调用 add() 方法将其加入到请求队列中
public Request add(Request request) {
// 将 Request 标记为属于此队列,并将其放入 mCurrentRequests 中
request.setRequestQueue(this);
synchronized (mCurrentRequests) {
mCurrentRequests.add(request);
}
// 让 Request 按照他们被添加的顺序执行
request.setSequence(getSequenceNumber());
request.addMarker(“add-to-queue”);
//如果请求不需要被缓存,就跳过缓存,直接进行网络请求
if (!request.shouldCache()) {
mNetworkQueue.add(request);
return request;
}
mCacheQueue.add(request);
return request;
}
可以看到,传入 Request 之后,会先判断该 Request 是否需要进行缓存,如果不需要就直接将其加入到网络请求队列,需要缓存则加入缓存队列。默认情况下,每条请求都是应该缓存的,当然我们也可以调用 Request 的 setShouldCache() 方法来进行设置。
Request 被添加到缓存队列中后,在后台等待的缓存线程就要开始运行起来了,我们看下 CacheDispatcher 的 run() 方法究竟是怎么实现的。
@Override
public void run() {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
// 初始化 Cache
mCache.initialize();
while (true) {
try {
processRequest();
} catch (InterruptedException e) {
if (mQuit) {
return;
}
}
}
}
private void processRequest() throws InterruptedException {
final Request<?> request = mCacheQueue.take();
request.addMarker(“cache-queue-take”);
// 如果请求已经取消了,我们直接结束该请求
if (request.isCanceled()) {
request.finish(“cache-discard-canceled”);
return;
}
// 从 Cache 中取出包含请求缓存数据的 Entry
Cache.Entry entry = mCache.get(request.getCacheKey());
if (entry == null) {
request.addMarker(“cache-miss”);
if (!mWaitingRequestManager.maybeAddToWaitingRequests(request)) {
mNetworkQueue.put(request);
}
return;
}
// 如果缓存的请求过期了,就将其添加到网络请求队列中
if (entry.isExpired()) {
request.addMarker(“cache-hit-expired”);
request.setCacheEntry(entry);
if (!mWaitingRequestManager.maybeAddToWaitingRequests(request)) {
mNetworkQueue.put(request);
}
return;
}
// 缓存的数据封装成 NetworkResponse
Response<?> response = request.parseNetworkResponse(
new NetworkResponse(entry.data, entry.responseHeaders));
if (!entry.refreshNeeded()) {
// 如果缓存没有过期就直接进行分发
mDelivery.postResponse(request, response);
} else {
// 重置该请求的 Entry
request.setCacheEntry(entry);
response.intermediate = true;
if (!mWaitingRequestManager.maybeAddToWaitingRequests(request)) {
mDelivery.postResponse(request, response, new Runnable() {
@Override
public void run() {
try {
mNetworkQueue.put(request);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
});
} else {
mDelivery.postResponse(request, response);
}
}
}
代码相对比较长,我在关键的地方已经打上注释了,在这里总结一下,可以看到在初始化了 Cache 之后,有一个 while(true) 循环,说明缓存线程是始终执行的,接着会在缓存中取出响应结果,如果为 null 的话,就将其加入到网络请求队列中,如果不为空的话,再判断该缓存是否已过期,已经过期则同样把这条请求加入到网络请求队列中,否则直接使用缓存中的数据。最后将数据进行解析,并进行分发。
看完 CacheDispathcer 的 run() 方法,我们接着看 NetworkDispatcher 的 run() 方法
@Override
public void run() {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
while (true) {
try {
processRequest();
} catch (InterruptedException e) {
if (mQuit) {
return;
}
}
}
}
private void processRequest() throws InterruptedException {
Request<?> request = mQueue.take();
long startTimeMs = SystemClock.elapsedRealtime();
try {
request.addMarker(“network-queue-take”);
// 如果 Request 已经取消了,那就不执行网络请求
if (request.isCanceled()) {
request.finish(“network-discard-cancelled”);
request.notifyListenerResponseNotUsable();
return;
}
addTrafficStatsTag(request);
// 执行网络请求
NetworkResponse networkResponse = mNetwork.performRequest(request);
// 如果服务器返回 304,而且我们已经分发过该 Request 的结果,那就不用进行第二次分发了
//(这里补充一下,304 代表服务器上的结果跟上次访问的结果是一样的,也就是说数据没有变化)
if (networkResponse.notModified && request.hasHadResponseDelivered()) {
request.finish(“not-modified”);
request.notifyListenerResponseNotUsable();
return;
}
// 在子线程解析返回的结果
Response<?> response = request.parseNetworkResponse(networkResponse);
// 如果需要的话,就将返回结果写入缓存
if (request.shouldCache() && response.cacheEntry != null) {
mCache.put(request.getCacheKey(), response.cacheEntry); }
// 分发响应结果
request.markDelivered();
mDelivery.postResponse(request, response);
request.notifyListenerResponseReceived(response);
} catch (VolleyError volleyError) {
request.notifyListenerResponseNotUsable();
} catch (Exception e) {
request.notifyListenerResponseNotUsable();
}
}
在 NetworkDispatcher 同样使用了 while(true),说明网络请求线程也是不断运行的。然后从网络队列里面取出 Request,再调用 Network 的 performRequest() 方法去发送网络请求。Network 其实是一个接口,这里具体的实现是 BasicNetwork,我们来看下它的 performRequest() 方法实现:
@Override
public NetworkResponse performRequest(Request<?> request) throws VolleyError {
long requestStart = SystemClock.elapsedRealtime();
while (true) {
HttpResponse httpResponse = null;
byte[] responseContents = null;
List
try {
Map<String, String> additionalRequestHeaders =
getCacheHeaders(request.getCacheEntry());
// 该注意的地方:调用 Stack 的 executeRequest 进行网络请求
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);
}
List
return new NetworkResponse(HttpURLConnection.HTTP_NOT_MODIFIED, entry.data,
true, SystemClock.elapsedRealtime() - requestStart, combinedHeaders);
}
// 有些返回结果是没有内容的,如:204,所以我们必须进行检查
InputStream inputStream = httpResponse.getContent();
if (inputStream != null) {
responseContents =
inputStreamToBytes(inputStream, httpResponse.getContentLength());
} else {
responseContents = new byte[0];
}
return new NetworkResponse(statusCode, responseContents, false,
SystemClock.elapsedRealtime() - requestStart, responseHeaders);
} catch (Exception e) {
// …
}
}
}
这个方法里面,基本上都是网络请求方面处理的细节,我们这篇文章,主要是梳理整体的流程,对细节方面先不深入。需要注意的是在我标注的第一个地方,调用了 Stack 的 executeRequest() 方法,这里的 Stack 就是之前调用 Volley.newRequestQueue() 所创建的实例,前面也说过了这个对象的内部是使用了 HttpURLConnection 或 HttpClient(已弃用)来进行网络请求。网络请求结束后将返回的数据封装成一个 NetworkResponse 对象进行返回。
在 NetworkDispatcher 接收到了这个 NetworkResponse 对象之后,又会调用 Request 的 parseNetworkResponse() 方法来对结果进行解析,然后将数据写入到缓存,最后调用 ExecutorDelivery 的 postResponse() 方法来回调解析后的数据,如下所示:
@Override
public void postResponse(Request<?> request, Response<?> response, Runnable runnable) {
request.markDelivered();
request.addMarker(“post-response”);
mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, runnable));
ction 或 HttpClient(已弃用)来进行网络请求。网络请求结束后将返回的数据封装成一个 NetworkResponse 对象进行返回。
在 NetworkDispatcher 接收到了这个 NetworkResponse 对象之后,又会调用 Request 的 parseNetworkResponse() 方法来对结果进行解析,然后将数据写入到缓存,最后调用 ExecutorDelivery 的 postResponse() 方法来回调解析后的数据,如下所示:
@Override
public void postResponse(Request<?> request, Response<?> response, Runnable runnable) {
request.markDelivered();
request.addMarker(“post-response”);
mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, runnable));