概述
今天从源码的角度来理解一下Volley中部分功能的实现。
源码
添加请求到请求队列
/**
*将请求添加到请求队列中
*/
public <T> Request<T> add(Request<T> request) {
// 标记此request属于当前这个请求队列
request.setRequestQueue(this);
synchronized (mCurrentRequests) {
//添加请求到队列中
mCurrentRequests.add(request);
}
// 为请求设置顺序编号.
request.setSequence(getSequenceNumber());
//添加标记
request.addMarker("add-to-queue");
// 如果请求不允许缓存,直接添加到网络请求队列
if (!request.shouldCache()) {
mNetworkQueue.add(request);
return request;
}
synchronized (mWaitingRequests) {
String cacheKey = request.getCacheKey();
if (mWaitingRequests.containsKey(cacheKey)) {
// 已经有请求正在被处理
Queue<Request<?>> stagedRequests = mWaitingRequests.get(cacheKey);
if (stagedRequests == null) {
stagedRequests = new LinkedList<Request<?>>();
}
//添加到相同的请求队列红
stagedRequests.add(request);
//添加到集合中
mWaitingRequests.put(cacheKey, stagedRequests);
if (VolleyLog.DEBUG) {
VolleyLog.v("Request for cacheKey=%s is in flight, putting on hold.", cacheKey);
}
} else {
// 创建新的等待当前请求的空队列
mWaitingRequests.put(cacheKey, null);
//将请求添加到缓存队列中
mCacheQueue.add(request);
}
return request;
}
}
给出一张图总结一下
接下来我们看finish方法
//当请求结束的时候会调用此方法
<T> void finish(Request<T> request) {
// 从正在请求的集合中移除该请求
synchronized (mCurrentRequests) {
mCurrentRequests.remove(request);
}
synchronized (mFinishedListeners) {
for (RequestFinishedListener<T> listener : mFinishedListeners) {
listener.onRequestFinished(request);
}
}
if (request.shouldCache()) {
synchronized (mWaitingRequests) {
String cacheKey = request.getCacheKey();
//从等待请求集合中移除对应的请求
Queue<Request<?>> waitingRequests = mWaitingRequests.remove(cacheKey);
if (waitingRequests != null) {
if (VolleyLog.DEBUG) {
VolleyLog.v("Releasing %d waiting requests for cacheKey=%s.",
waitingRequests.size(), cacheKey);
}
//交给缓存队列去处理
mCacheQueue.addAll(waitingRequests);
}
}
}
}
缓存分发线程
public class CacheDispatcher extends Thread {
private static final boolean DEBUG = VolleyLog.DEBUG;
/** 缓存队列. */
private final BlockingQueue<Request<?>> mCacheQueue;
/** 网络请求队列. */
private final BlockingQueue<Request<?>> mNetworkQueue;
/** 需要读取的缓存. */
private final Cache mCache;
/** 用来分发结果. */
private final ResponseDelivery mDelivery;
/** 退出标志. */
private volatile boolean mQuit = false;
/**
* 为成员变量赋值
*/
public CacheDispatcher(
BlockingQueue<Request<?>> cacheQueue, BlockingQueue<Request<?>> networkQueue,
Cache cache, ResponseDelivery delivery) {
mCacheQueue = cacheQueue;
mNetworkQueue = networkQueue;
mCache = cache;
mDelivery = delivery;
}
/**
* 强制分发线程退出,这不保证请求队列中的请求能够被处理
*/
public void quit() {
mQuit = true;
interrupt();
}
@Override
public void run() {
if (DEBUG) VolleyLog.v("start new dispatcher");
//设置线程优先级 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
// 初始化缓存,具体实现在DiskBasedCache中,我们稍后分析
mCache.initialize();
while (true) {
try {
//不断循环,从缓存队列中取出请求
// at least one is available.
final Request<?> request = mCacheQueue.take();
request.addMarker("cache-queue-take");
if (request.isCanceled()) {
request.finish("cache-discard-canceled");
continue;
}
// 从缓存中取出缓存实体
Cache.Entry entry = mCache.get(request.getCacheKey());
if (entry == null) {
request.addMarker("cache-miss");
// 缓存不存在,添加到网络请求队列中
mNetworkQueue.put(request);
continue;
}
// 缓存过期,添加到请求队列
if (entry.isExpired()) {
request.addMarker("cache-hit-expired");
request.setCacheEntry(entry);
mNetworkQueue.put(request);
continue;
}
// 缓存击中,调用request的方法进行数据解析
request.addMarker("cache-hit");
Response<?> response = request.parseNetworkResponse(
new NetworkResponse(entry.data, entry.responseHeaders));
request.addMarker("cache-hit-parsed");
if (!entry.refreshNeeded()) {
// 缓存结果完全新鲜,投递结果
mDelivery.postResponse(request, response);
} else {
// 不是特别新鲜,我们同样投递结果,并且发送到网络请求线程进行刷新
request.addMarker("cache-hit-refresh-needed");
request.setCacheEntry(entry);
//标记请求为中级.
response.intermediate = true;
// 将响应投递给用户,并且将请求添加到网络请求队列。
mDelivery.postResponse(request, response, new Runnable() {
@Override
public void run() {
try {
mNetworkQueue.put(request);
} catch (InterruptedException e) {
// Not much we can do about this.
}
}
});
}
} catch (InterruptedException e) {
// We may have been interrupted because it was time to quit.
if (mQuit) {
return;
}
continue;
}
}
}
}