Volley 是 Google 推出的 Android 異步網(wǎng)絡(luò)請(qǐng)求框架和圖片加載框架。在 Google I/O 2013 大會(huì)上發(fā)布的,現(xiàn)在連android系統(tǒng)中內(nèi)部也是使用了Volley作為其網(wǎng)絡(luò)的請(qǐng)求框架,谷歌出品,必屬精品,所以有必要進(jìn)行一次梳理其實(shí)現(xiàn)的總體過(guò)程,學(xué)習(xí)其設(shè)計(jì)框架的思路也是必要的(文章適合知道基本使用Volley的同學(xué)觀看)。
<h3>Volley</h3>
一般我們都會(huì)在app初始化的時(shí)候調(diào)用如下代碼進(jìn)行初始化Volley,下面就從該方法當(dāng)做閱讀入口進(jìn)行逐一跟蹤:
mRequestQueue = Volley.newRequestQueue(this);
在調(diào)用Volley.newRequestQueue(this)時(shí),最終調(diào)用到如下代碼:
/**
* Creates a default instance of the worker pool and calls {@link RequestQueue#start()} on it.
* You may set a maximum size of the disk cache in bytes.
*HttpStack是用來(lái)進(jìn)行網(wǎng)絡(luò)請(qǐng)求封裝的類(lèi),傳入null代表默認(rèn)
*maxDiskCacheBytes為最大磁盤(pán)緩存,傳入-1使用默認(rèn)大小
*/
public static RequestQueue newRequestQueue(Context context, HttpStack stack, int maxDiskCacheBytes) {
//構(gòu)造緩存區(qū)域
File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR);
String userAgent = "volley/0";
try {
String packageName = context.getPackageName();
PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0);
userAgent = packageName + "/" + info.versionCode;
} catch (NameNotFoundException e) {
}
//我們可以傳入okttp來(lái)充當(dāng)我們的httpStack
if (stack == null) {
//使用Volley默認(rèn)封裝的stack,依靠android版本來(lái)決定使用不同的connection來(lái)進(jìn)行網(wǎng)絡(luò)請(qǐng)求
if (Build.VERSION.SDK_INT >= 9) {
stack = new HurlStack();
} else {
// Prior to Gingerbread, HttpUrlConnection was unreliable.
// See: http://android-developers.blogspot.com/2011/09/androids-http-clients.html
stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));
}
}
Network network = new BasicNetwork(stack);
RequestQueue queue;
if (maxDiskCacheBytes <= -1)
{
// No maximum size specified
queue = new RequestQueue(new DiskBasedCache(cacheDir), network);
}
else
{
// Disk cache size specified
queue = new RequestQueue(new DiskBasedCache(cacheDir, maxDiskCacheBytes), network);
}
queue.start();
return queue;
}
在newRequestQueue?方法中進(jìn)行了相關(guān)必要參數(shù)的初始化的工作,其中包括:
- 緩存區(qū)域的初始化
- HttpStack的初始化
- Network的初始化
- RequestQueue的初始化,最終調(diào)用其start()方法
Stack 詳解
在Volley中如果沒(méi)有傳遞任何HttpStack則會(huì)使用了兩種stack來(lái)進(jìn)行不同android版本(SDK_INT >= 9?HurlStack:HttpClientStack)的適配工作:HurlStack和HttpClientStack,兩種stack都實(shí)現(xiàn)了HttpStack接口,接口定義如下:
public interface HttpStack {
//請(qǐng)求處理方法
public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)
throws IOException, AuthFailureError;
}
在接口中定義performRequest方法,在其子類(lèi)中實(shí)現(xiàn)了對(duì)于http請(qǐng)求的封裝的操作,以此來(lái)查看對(duì)應(yīng)實(shí)現(xiàn)子類(lèi)的performRequest方法。
在HurlStack中關(guān)于performRequest(…)的實(shí)現(xiàn):
@Override
public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)
throws IOException, AuthFailureError {
String url = request.getUrl();
//存放請(qǐng)求頭
HashMap<String, String> map = new HashMap<String, String>();
map.putAll(request.getHeaders());
map.putAll(additionalHeaders);
//是否重寫(xiě)url
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進(jìn)行網(wǎng)絡(luò)請(qǐng)求
HttpURLConnection connection = openConnection(parsedUrl, request);
for (String headerName : map.keySet()) {
connection.addRequestProperty(headerName, map.get(headerName));
}
//設(shè)置請(qǐng)求方法:GET ,POST, ect
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);
//將返回的數(shù)據(jù)流寫(xiě)入response
response.setEntity(entityFromConnection(connection));
//獲取返回的請(qǐng)求頭
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;
}
HurlStack使用HttpURLConnection進(jìn)行Http請(qǐng)求的過(guò)程,步驟是基本的網(wǎng)絡(luò)請(qǐng)求的過(guò)程,設(shè)置請(qǐng)求頭->包裝Url->打開(kāi)連接->設(shè)置請(qǐng)求方法->獲取數(shù)據(jù)已經(jīng)請(qǐng)求狀態(tài)->將數(shù)據(jù)流存入HttpResponse,最終返回一個(gè)HttpResponse。
HttpClientStack中關(guān)于performRequest(…)的實(shí)現(xiàn):
@Override
public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)
throws IOException, AuthFailureError {
//構(gòu)造請(qǐng)求參數(shù)
HttpUriRequest httpRequest = createHttpRequest(request, additionalHeaders);
//添加請(qǐng)求頭
addHeaders(httpRequest, additionalHeaders);
addHeaders(httpRequest, request.getHeaders());
onPrepareRequest(httpRequest);
HttpParams httpParams = httpRequest.getParams();
int timeoutMs = request.getTimeoutMs();
// TODO: Reevaluate this connection timeout based on more wide-scale
// data collection and possibly different for wifi vs. 3G.
HttpConnectionParams.setConnectionTimeout(httpParams, 5000);
HttpConnectionParams.setSoTimeout(httpParams, timeoutMs);
return mClient.execute(httpRequest);
}
HttpClientStack?執(zhí)行的大體過(guò)程與HurlStack基本上一致,通過(guò)一系列操作最終調(diào)用AndroidHttpClient.execute(httpRequest)返回一個(gè)HttpResponse。
HttpStack封裝了http請(qǐng)求的過(guò)程,并且只管http請(qǐng)求,滿(mǎn)足設(shè)計(jì)模式中單一責(zé)任的原則,并且向外提供接口HttpStack方便使用者定制自身的HttpStack類(lèi)來(lái)進(jìn)行請(qǐng)求的過(guò)程,如:可以用OkhttpClient來(lái)進(jìn)行http請(qǐng)求的過(guò)程,這對(duì)于Volley的整個(gè)流程是不受影響。
Network
public interface Network {
/**
* Performs the specified request.
* @param request Request to process
* @return A {@link NetworkResponse} with data and caching metadata; will never be null
* @throws VolleyError on errors
*/
public NetworkResponse performRequest(Request<?> request) throws VolleyError;
}
Network接口中定義了performRequest用于接收一個(gè)具體的Request請(qǐng)求,其實(shí)現(xiàn)類(lèi)是BasicNetwork,我們直接查看performRequest方法:
@Override
public NetworkResponse performRequest(Request<?> request) throws VolleyError {
long requestStart = SystemClock.elapsedRealtime();
//死循環(huán)
while (true) {
HttpResponse httpResponse = null;
byte[] responseContents = null;
Map<String, String> responseHeaders = Collections.emptyMap();
try {
// Gather headers.
Map<String, String> headers = new HashMap<String, String>();
addCacheHeaders(headers, request.getCacheEntry());
//通過(guò)HttpStack獲得HttpResponse
httpResponse = mHttpStack.performRequest(request, headers);
StatusLine statusLine = httpResponse.getStatusLine();
int statusCode = statusLine.getStatusCode();
//返回的請(qǐng)求頭
responseHeaders = convertHeaders(httpResponse.getAllHeaders());
//請(qǐng)求返回的狀態(tài)碼處理
if (statusCode == HttpStatus.SC_NOT_MODIFIED) {
Entry entry = request.getCacheEntry();
if (entry == null) {
return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED, null,
responseHeaders, true,
SystemClock.elapsedRealtime() - requestStart);
}
entry.responseHeaders.putAll(responseHeaders);
return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED, entry.data,
entry.responseHeaders, true,
SystemClock.elapsedRealtime() - requestStart);
}
// Handle moved resources
if (statusCode == HttpStatus.SC_MOVED_PERMANENTLY || statusCode == HttpStatus.SC_MOVED_TEMPORARILY) {
String newUrl = responseHeaders.get("Location");
request.setRedirectUrl(newUrl);
}
// 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,
SystemClock.elapsedRealtime() - requestStart);
...
int statusCode = 0;
NetworkResponse networkResponse = null;
if (httpResponse != null) {
statusCode = httpResponse.getStatusLine().getStatusCode();
} else {
throw new NoConnectionError(e);
}
if (statusCode == HttpStatus.SC_MOVED_PERMANENTLY ||
statusCode == HttpStatus.SC_MOVED_TEMPORARILY) {
VolleyLog.e("Request at %s has been redirected to %s", request.getOriginUrl(), request.getUrl());
} else {
VolleyLog.e("Unexpected response code %d for %s", statusCode, request.getUrl());
}
if (responseContents != null) {
networkResponse = new NetworkResponse(statusCode, responseContents,
responseHeaders, false, SystemClock.elapsedRealtime() - requestStart);
...
}
}
}
在BasicNetwork中,我們可以看到其通過(guò)寫(xiě)了一個(gè)死循環(huán)來(lái)保證重復(fù)請(qǐng)求的操作直到報(bào)錯(cuò)或者返回結(jié)果,在其中他會(huì)調(diào)用mHttpStack.performRequest(request, headers)來(lái)獲得一個(gè)HttpResponse,調(diào)用entityToBytes()將entity轉(zhuǎn)換成一個(gè)字節(jié)數(shù)組,并且獲取相關(guān)參數(shù)(header,statusCode .etc)去進(jìn)一步的構(gòu)造出一個(gè)NetworkResponse,并且返回:
public NetworkResponse(int statusCode, byte[] data, Map<String, String> headers,
boolean notModified, long networkTimeMs) {
this.statusCode = statusCode;
this.data = data;
this.headers = headers;
this.notModified = notModified;
this.networkTimeMs = networkTimeMs;
}
public NetworkResponse(int statusCode, byte[] data, Map<String, String> headers,
boolean notModified) {
this(statusCode, data, headers, notModified, 0);
}
public NetworkResponse(byte[] data) {
this(HttpStatus.SC_OK, data, Collections.<String, String>emptyMap(), false, 0);
}
public NetworkResponse(byte[] data, Map<String, String> headers) {
this(HttpStatus.SC_OK, data, headers, false, 0);
}
/**Http狀態(tài)碼 */
public final int statusCode;
/**網(wǎng)絡(luò)請(qǐng)求返回的字節(jié)數(shù)據(jù) */
public final byte[] data;
/**返回的請(qǐng)求頭 */
public final Map<String, String> headers;
/** 是否返回的304的狀態(tài)碼*/
public final boolean notModified;
/** 請(qǐng)求耗時(shí). */
public final long networkTimeMs;
RequestQueue
RequestQueue是一個(gè)請(qǐng)求隊(duì)列,Volley將所有Request請(qǐng)求維護(hù)在此請(qǐng)求對(duì)列當(dāng)中,內(nèi)部有兩個(gè)對(duì)應(yīng)緩存和網(wǎng)絡(luò)的請(qǐng)求阻塞隊(duì)列來(lái)對(duì)Request進(jìn)行維護(hù),并且通過(guò)不同的Dispatcher(extends Thread)進(jìn)行進(jìn)一步的請(qǐng)求結(jié)果的處理,主要代碼如下:
public class RequestQueue {
/** 所有請(qǐng)求完成后的回調(diào) */
public static interface RequestFinishedListener<T> {
/** Called when a request has finished processing. */
public void onRequestFinished(Request<T> request);
}
...
//等待請(qǐng)求的Request,如果一個(gè)請(qǐng)求可以進(jìn)行緩存,則后續(xù)的相同CacheKey的請(qǐng)求,將進(jìn)入此等待隊(duì)列。
private final Map<String, Queue<Request<?>>> mWaitingRequests =
new HashMap<String, Queue<Request<?>>>();
//當(dāng)前請(qǐng)求以及未完成的請(qǐng)求
private final Set<Request<?>> mCurrentRequests = new HashSet<Request<?>>();
/** 緩存請(qǐng)求阻塞隊(duì)列 */
private final PriorityBlockingQueue<Request<?>> mCacheQueue =
new PriorityBlockingQueue<Request<?>>();
/** 網(wǎng)絡(luò)請(qǐng)求阻塞隊(duì)列 */
private final PriorityBlockingQueue<Request<?>> mNetworkQueue =
new PriorityBlockingQueue<Request<?>>();
//網(wǎng)絡(luò)請(qǐng)求線程池大小
private static final int DEFAULT_NETWORK_THREAD_POOL_SIZE = 4;
...
//網(wǎng)絡(luò)dispatcher數(shù)組
private NetworkDispatcher[] mDispatchers;
//緩存dispatcher
private CacheDispatcher mCacheDispatcher;
//Request完成listener
private List<RequestFinishedListener> mFinishedListeners =
new ArrayList<RequestFinishedListener>();
public RequestQueue(Cache cache, Network network, int threadPoolSize,
ResponseDelivery delivery) {
mCache = cache;
mNetwork = network;
//初始化網(wǎng)絡(luò)Dispatcher
mDispatchers = new NetworkDispatcher[threadPoolSize];
mDelivery = delivery;
}
/**
* start()方法中啟動(dòng)了緩存dispatcher跟網(wǎng)絡(luò)請(qǐng)求dispatcher,用來(lái)處理數(shù)據(jù)請(qǐng)求,
* 如果緩存中有數(shù)據(jù),則直接在緩存中獲取數(shù)據(jù),緩存中沒(méi)有數(shù)據(jù)則從網(wǎng)絡(luò)中獲取數(shù)據(jù)。
*/
public void start() {
stop(); // Make sure any currently running dispatchers are stopped.
// 啟動(dòng)緩存請(qǐng)求隊(duì)列
mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery);
mCacheDispatcher.start();
// Create network dispatchers (and corresponding threads) up to the pool size.
//創(chuàng)造網(wǎng)絡(luò)請(qǐng)求隊(duì)列
for (int i = 0; i < mDispatchers.length; i++) {
NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork,
mCache, mDelivery);
mDispatchers[i] = networkDispatcher;
networkDispatcher.start();
}
}
...
/**
* 添加新的請(qǐng)求到請(qǐng)求對(duì)列當(dāng)中
*/
public <T> Request<T> add(Request<T> request) {
...
}
...
<T> void finish(Request<T> request) {
// Remove from the set of requests currently being processed.
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) {
mCacheQueue.addAll(waitingRequests);
}
}
}
}
....
}
RequestQueue是Volley中最核心的類(lèi),掌管著所有request的請(qǐng)求和調(diào)度的過(guò)程,可以說(shuō)是一個(gè)中轉(zhuǎn)器的作用,我們從剛開(kāi)始的start()方法看起:
/**
* start()方法中啟動(dòng)了緩存dispatcher跟網(wǎng)絡(luò)請(qǐng)求dispatcher,用來(lái)處理數(shù)據(jù)請(qǐng)求,
* 如果緩存中有數(shù)據(jù),則直接在緩存中獲取數(shù)據(jù),緩存中沒(méi)有數(shù)據(jù)則從網(wǎng)絡(luò)中獲取數(shù)據(jù)。
*/
public void start() {
stop(); // Make sure any currently running dispatchers are stopped.
// 啟動(dòng)緩存請(qǐng)求隊(duì)列
mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery);
mCacheDispatcher.start();
//創(chuàng)造網(wǎng)絡(luò)請(qǐng)求隊(duì)列
for (int i = 0; i < mDispatchers.length; i++) {
NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork,
mCache, mDelivery);
mDispatchers[i] = networkDispatcher;
networkDispatcher.start();
}
}
在調(diào)用start()時(shí)候,主要做了兩件事情:
- 調(diào)用stop()終止所有的dispatcher
- 初始化所有的dispatcher,并且start(),dispatcher都是繼承于Thread的類(lèi)
一般我們進(jìn)行請(qǐng)求時(shí)候,都是使用的add(Request)方法來(lái)進(jìn)行,所以接下來(lái)就查看一下這個(gè)方法的實(shí)現(xiàn)過(guò)程:
/**
* 添加新的請(qǐng)求到請(qǐng)求對(duì)列當(dāng)中
*/
public <T> Request<T> add(Request<T> request) {
// 設(shè)置對(duì)應(yīng)關(guān)聯(lián)
request.setRequestQueue(this);
//添加到CurrentRequests中
synchronized (mCurrentRequests) {
mCurrentRequests.add(request);
}
// 按添加到請(qǐng)求隊(duì)列的順序請(qǐng)求數(shù)據(jù)
request.setSequence(getSequenceNumber());
//添加標(biāo)志
request.addMarker("add-to-queue");
//當(dāng)前request是否有緩存過(guò),沒(méi)有直接加入到網(wǎng)絡(luò)請(qǐng)求隊(duì)列中
if (!request.shouldCache()) {
mNetworkQueue.add(request);
return request;
}
synchronized (mWaitingRequests) {
//得到緩存key(該key為medthod+url的單一key)
String cacheKey = request.getCacheKey();
//是否包含該緩存key
if (mWaitingRequests.containsKey(cacheKey)) {
// There is already a request in flight. Queue up.
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 {
// Insert 'null' queue for this cacheKey, indicating there is now a request in
// flight.
mWaitingRequests.put(cacheKey, null);
mCacheQueue.add(request);
}
return request;
}
}
在add()方法中主要的過(guò)程如圖所示:

主要實(shí)現(xiàn)思路如下:
- 添加到mCurrentRequests中,mCurrentRequests當(dāng)前請(qǐng)求以及未完成的請(qǐng)求的set,所有通過(guò)add()進(jìn)來(lái)的都會(huì)加入到?此set的當(dāng)中。
- 通過(guò)request.shouldCache()來(lái)判斷是否需要緩存request,如果不需要?jiǎng)t直接加入到網(wǎng)絡(luò)請(qǐng)求隊(duì)列當(dāng)中,return;如果需要緩存當(dāng)前request則判斷mWaitingRequests是否包含了該request的CacheKey的setKey,如果有,則加入相同的隊(duì)列當(dāng)中,則put到mWaitingRequests當(dāng)中,如果沒(méi)有包含了該request的CacheKey的setKey,置空與當(dāng)前request的相同的queue(mWaitingRequests.put(cacheKey, null)),然后把request加入到緩存請(qǐng)求對(duì)列當(dāng)中。
add()方法中主要是為了找到request的存放地,是網(wǎng)絡(luò)請(qǐng)求隊(duì)列還是緩存請(qǐng)求隊(duì)列,在判斷是否加入到緩存請(qǐng)求隊(duì)列時(shí)維護(hù)了一個(gè)mWaitingRequests集合來(lái)管理相同的請(qǐng)求,如果cacheKey相同,則不會(huì)加入到任何請(qǐng)對(duì)隊(duì)列當(dāng)中,然后加入到mWaitingRequests存有相同SetKey的SetValue中,掛起。
<h4>Dispatcher</h4>
返回RequestQueue.start()中,這里會(huì)將CacheDispatcher和NetworkDispatchers啟動(dòng),兩種Dispatcher共同繼承于Thread來(lái)處理延時(shí)操作--網(wǎng)絡(luò)請(qǐng)求和緩存請(qǐng)求的過(guò)程,這里只詳細(xì)講述CacheDispatcher的run()過(guò)程,NetworkDispatchers只以簡(jiǎn)述的形式講述。
CacheDispatcher在run方法中寫(xiě)死一個(gè)無(wú)限循環(huán),可以類(lèi)比成handler機(jī)制中的Looper.loop()的設(shè)計(jì)思路,不斷的輪訓(xùn)緩存隊(duì)列(mCacheQueue),從中取出request將其傳遞給mDelivery來(lái)進(jìn)行處理。
@Override
public void run() {
//設(shè)置線程優(yōu)先級(jí)
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
// 初始化緩存相關(guān)參數(shù)
mCache.initialize();
while (true) {
try {
//從mCacheQueue取緩存
final Request<?> request = mCacheQueue.take();
//添加緩存過(guò)的標(biāo)記
request.addMarker("cache-queue-take");
// 當(dāng)前request是否取消了
if (request.isCanceled()) {
request.finish("cache-discard-canceled");
continue;
}
// Attempt to retrieve this item from cache.
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 it is completely expired, just send it to the network.
if (entry.isExpired()) {
request.addMarker("cache-hit-expired");
request.setCacheEntry(entry);
mNetworkQueue.put(request);
continue;
}
// We have a cache hit; parse its data for delivery back to the request.
request.addMarker("cache-hit");
Response<?> response = request.parseNetworkResponse(
new NetworkResponse(entry.data, entry.responseHeaders));
request.addMarker("cache-hit-parsed");
//緩存數(shù)據(jù)是否需要更新
if (!entry.refreshNeeded()) {
// Completely unexpired cache hit. Just deliver the response.
mDelivery.postResponse(request, response);
} else {
// Soft-expired cache hit. We can deliver the cached response,
// but we need to also send the request to the network for
// refreshing.
request.addMarker("cache-hit-refresh-needed");
request.setCacheEntry(entry);
// Mark the response as intermediate.
response.intermediate = true;
// Post the intermediate response back to the user and have
// the delivery then forward the request along to the network.
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;
}
}
}
run方法內(nèi)循環(huán)的過(guò)程中每次從mCacheQueue拿出一個(gè)request請(qǐng)求,對(duì)其添加已經(jīng)訪問(wèn)過(guò)的marker,如果在期間request被取消了,最終會(huì)調(diào)用RequestQueue.finish()方法從mCurrentRequests中remove掉,一次循環(huán)完成;如果request沒(méi)被取消則從緩存中獲取數(shù)據(jù),并且判斷是否為空,如果為空則加入網(wǎng)絡(luò)隊(duì)列中重新請(qǐng)求,一次循環(huán)完成;如果不為空判斷是否過(guò)期,過(guò)期了則加入網(wǎng)絡(luò)隊(duì)列中重新請(qǐng)求,一次循環(huán)完成;如果不過(guò)期判斷是否需要更新緩存,需要?jiǎng)t加入網(wǎng)絡(luò)隊(duì)列中重新請(qǐng)求,否則調(diào)用mDelivery.postResponse()完成數(shù)據(jù)傳遞的過(guò)程,執(zhí)行圖如下:

NetworkDispatcher也繼承自Thread接口,run方法實(shí)現(xiàn)代碼如下:
@Override
public void run() {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
while (true) {
long startTimeMs = SystemClock.elapsedRealtime();
Request<?> request;
try {
// Take a request from the queue.
request = mQueue.take();
} catch (InterruptedException e) {
// We may have been interrupted because it was time to quit.
if (mQuit) {
return;
}
continue;
}
try {
request.addMarker("network-queue-take");
// If the request was cancelled already, do not perform the
// network request.
if (request.isCanceled()) {
request.finish("network-discard-cancelled");
continue;
}
addTrafficStatsTag(request);
//獲取到請(qǐng)求結(jié)果
NetworkResponse networkResponse = mNetwork.performRequest(request);
request.addMarker("network-http-complete");
// If the server returned 304 AND we delivered a response already,
// we're done -- don't deliver a second identical response.
if (networkResponse.notModified && request.hasHadResponseDelivered()) {
request.finish("not-modified");
continue;
}
// Parse the response here on the worker thread.
Response<?> response = request.parseNetworkResponse(networkResponse);
request.addMarker("network-parse-complete");
//是否緩存結(jié)果
if (request.shouldCache() && response.cacheEntry != null) {
mCache.put(request.getCacheKey(), response.cacheEntry);
request.addMarker("network-cache-written");
}
// Post the response back.
request.markDelivered();
//交付給mDelivery
mDelivery.postResponse(request, response);
} catch (VolleyError volleyError) {
volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs);
parseAndDeliverNetworkError(request, volleyError);
} catch (Exception e) {
VolleyLog.e(e, "Unhandled exception %s", e.toString());
VolleyError volleyError = new VolleyError(e);
volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs);
mDelivery.postError(request, volleyError);
}
}
}
在NetworkDispatcher中主要通過(guò)Network接口performRequest()方法獲得一個(gè)NetworkResponse,進(jìn)而在轉(zhuǎn)換成Delivery.postResponse()可接受的Request對(duì)象進(jìn)行傳遞,其中會(huì)判斷是否需要緩存該request以及相關(guān)error的捕獲并且傳遞給Delivery.postError()。
<h3>ResponseDelivery</h3>
無(wú)論是CacheDispatcher還是NetworkDispatcher,最終的結(jié)果都是交付由ResponseDelivery接口實(shí)現(xiàn)類(lèi)來(lái)進(jìn)行實(shí)現(xiàn):
public interface ResponseDelivery {
/**
* Parses a response from the network or cache and delivers it.
*/
public void postResponse(Request<?> request, Response<?> response);
/**
* 處理從緩存和網(wǎng)絡(luò)上獲取的數(shù)據(jù)
*/
public void postResponse(Request<?> request, Response<?> response, Runnable runnable);
/**
*處理錯(cuò)誤的情況
*/
public void postError(Request<?> request, VolleyError error);
}
其具體實(shí)現(xiàn)類(lèi)為ExecutorDelivery中,其代碼如下:
/**
* 將請(qǐng)求結(jié)果傳遞給回調(diào)接口
*/
public class ExecutorDelivery implements ResponseDelivery {
/** Used for posting responses, typically to the main thread. */
private final Executor mResponsePoster;
/**
* 傳入Handler的原因,目的是為了與主線程進(jìn)行交互
* @param handler {@link Handler} to post responses on
*/
public ExecutorDelivery(final Handler handler) {
// Make an Executor that just wraps the handler.
mResponsePoster = new Executor() {
@Override
public void execute(Runnable command) {
handler.post(command);
}
};
}
...
@Override
public void postResponse(Request<?> request, Response<?> response, Runnable runnable) {
//request傳遞標(biāo)記
request.markDelivered();
request.addMarker("post-response");
mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, runnable));
}
@Override
public void postError(Request<?> request, VolleyError error) {
request.addMarker("post-error");
Response<?> response = Response.error(error);
mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, null));
}
/**
* A Runnable used for delivering network responses to a listener on the
* main thread.
*/
@SuppressWarnings("rawtypes")
private class ResponseDeliveryRunnable implements Runnable {
private final Request mRequest;
private final Response mResponse;
private final Runnable mRunnable;
public ResponseDeliveryRunnable(Request request, Response response, Runnable runnable) {
mRequest = request;
mResponse = response;
mRunnable = runnable;
}
@SuppressWarnings("unchecked")
@Override
public void run() {
// If this request has canceled, finish it and don't deliver.
if (mRequest.isCanceled()) {
mRequest.finish("canceled-at-delivery");
return;
}
// 傳遞請(qǐng)求的結(jié)果,對(duì)應(yīng)調(diào)用相應(yīng)的回調(diào)接口,看mRequest對(duì)應(yīng)實(shí)現(xiàn)類(lèi)
//如果是StringRequest,則回調(diào)對(duì)應(yīng)接口。
if (mResponse.isSuccess()) {
mRequest.deliverResponse(mResponse.result);
} else {
mRequest.deliverError(mResponse.error);
}
// If this is an intermediate response, add a marker, otherwise we're done
// and the request can be finished.
if (mResponse.intermediate) {
mRequest.addMarker("intermediate-response");
} else {
mRequest.finish("done");
}
// If we have been provided a post-delivery runnable, run it.
if (mRunnable != null) {
mRunnable.run();
}
}
}
}
從Dispatcher那邊獲取到request和response最終傳遞到內(nèi)部類(lèi)ResponseDeliveryRunnable中進(jìn)行處理,如果request是被finish的則丟棄傳遞,否則調(diào)用Request的對(duì)應(yīng)的deliverResponse或者deliverError方法。這里要注意以下,該方法中傳遞了handler變量進(jìn)來(lái),這個(gè)變量是主線程的handler,也就保證了request的回調(diào)從工作線程切換回了主線程,其初始化代碼如下:
public RequestQueue(Cache cache, Network network, int threadPoolSize) {
this(cache, network, threadPoolSize,
new ExecutorDelivery(new Handler(Looper.getMainLooper())));
}
<h4>Request</h4>
Request類(lèi)是一個(gè)抽象方法,其子類(lèi)實(shí)現(xiàn)主要有:StringRequest,JsonRequest,ImageRequest .etc ,為了簡(jiǎn)單查看后續(xù)步驟,我們拿StringRequest來(lái)查看:
/**
* Delivers error message to the ErrorListener that the Request was
* initialized with.
*
* @param error Error details
*/
public void deliverError(VolleyError error) {
if (mErrorListener != null) {
mErrorListener.onErrorResponse(error);
}
}
@Override
protected void deliverResponse(String response) {
if (mListener != null) {
mListener.onResponse(response);
}
}
到這里就執(zhí)行到了最終的回調(diào),所有的過(guò)程也就完成了。
<h4>個(gè)人總結(jié)</h4>
個(gè)人認(rèn)為volley的精髓在于面向接口編程,具有非常廣闊的拓展性,開(kāi)發(fā)者完全可以自主寫(xiě)一套自己的volley邏輯,充分解耦了各個(gè)模塊,使用組合的方式進(jìn)行編程,是我們學(xué)習(xí)設(shè)計(jì)代碼的一個(gè)非常好的庫(kù)吧。
附上Volley過(guò)程圖:
