前言
經(jīng)常接觸Android網(wǎng)絡(luò)編程的我們,對(duì)于Volley肯定不陌生性雄,但我們不禁要問(wèn)办悟,對(duì)于Volley我們真的很了解嗎?Volley的內(nèi)部是怎樣實(shí)現(xiàn)的铺然?為什么幾行代碼就能快速搭建好一個(gè)網(wǎng)絡(luò)請(qǐng)求赋铝?我們不但要知其然革骨,也要知其所以然,抱著這樣的目的筑凫,本文主要詳細(xì)講述Volley的源碼巍实,對(duì)內(nèi)部流程進(jìn)行詳細(xì)解析。
Part 1.從RequestQueue說(shuō)起
(1)還記得搭建請(qǐng)求的第一步是什么嗎瓦盛?是新建一個(gè)請(qǐng)求隊(duì)列,比如說(shuō)這樣:
RequestQueue queue = Volley.newRequestQueue(context)
雖然表面上只是一句代碼的事情嘱吗,但是背后做了很多準(zhǔn)備工作,我們追蹤源碼绕德,找到Volley#newRequestQueue()方法:
/**
* 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.
*
* @param context A {@link Context} to use for creating the cache dir.
* @param stack An {@link HttpStack} to use for the network, or null for default.
* @param maxDiskCacheBytes the maximum size of the disk cache, in bytes. Use -1 for default size.
* @return A started {@link RequestQueue} instance.
*/
public static RequestQueue newRequestQueue(Context context, HttpStack stack, int maxDiskCacheBytes) {
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) {
}
/**
* 根據(jù)不同的系統(tǒng)版本號(hào)實(shí)例化不同的請(qǐng)求類踪蹬,如果版本號(hào)小于9,用HttpClient
* 如果版本號(hào)大于9夺蛇,用HttpUrlConnection
*/
if (stack == null) {
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));
}
}
//把實(shí)例化的stack傳遞進(jìn)BasicNetwork娶聘,實(shí)例化Network
Network network = new BasicNetwork(stack);
RequestQueue queue;
if (maxDiskCacheBytes <= -1){
// No maximum size specified
//實(shí)例化RequestQueue類
queue = new RequestQueue(new DiskBasedCache(cacheDir), network);
}
else {
// Disk cache size specified
queue = new RequestQueue(new DiskBasedCache(cacheDir, maxDiskCacheBytes), network);
}
//調(diào)用RequestQueue的start()方法
queue.start();
return queue;
}
首先我們看參數(shù)宦焦,有三個(gè),實(shí)際上我們默認(rèn)使用了只有一個(gè)參數(shù)context的方法,這個(gè)是對(duì)應(yīng)的重載方法歹篓,最終調(diào)用的是三個(gè)參數(shù)的方法庄撮,context是上下文環(huán)境;stack代表需要使用的網(wǎng)絡(luò)連接請(qǐng)求類毙籽,這個(gè)一般不用設(shè)置洞斯,方法內(nèi)部會(huì)根據(jù)當(dāng)前系統(tǒng)的版本號(hào)調(diào)用不同的網(wǎng)絡(luò)連接請(qǐng)求類(HttpUrlConnection和HttpClient);最后一個(gè)參數(shù)是緩存的大小坑赡。接著我們看方法內(nèi)部烙如,這里先創(chuàng)建了緩存文件,然后根據(jù)不同的系統(tǒng)版本號(hào)實(shí)例化不同的請(qǐng)求類毅否,用stack引用這個(gè)類。接著又實(shí)例化了一個(gè)BasicNetwork,這個(gè)類在下面會(huì)說(shuō)到。然后到了實(shí)際實(shí)例化請(qǐng)求隊(duì)列的地方:new RequestQueue()翻默,這里接收兩個(gè)參數(shù)翘单,分別是緩存和network(BasicNetwork)。實(shí)例化RequestQueue后,調(diào)用了start()方法堪滨,最后返回這個(gè)RequestQueue。
≈坪洹(2)我們跟著RequestQueue看看它的構(gòu)造器做了哪些工作:
/**
* Creates the worker pool. Processing will not begin until {@link #start()} is called.
*
* @param cache A Cache to use for persisting responses to disk
* @param network A Network interface for performing HTTP requests
* @param threadPoolSize Number of network dispatcher threads to create
* @param delivery A ResponseDelivery interface for posting responses and errors
*/
public RequestQueue(Cache cache, Network network, int threadPoolSize,
ResponseDelivery delivery) {
mCache = cache;
mNetwork = network;
//實(shí)例化網(wǎng)絡(luò)請(qǐng)求數(shù)組,數(shù)組大小默認(rèn)是4
mDispatchers = new NetworkDispatcher[threadPoolSize];
mDelivery = delivery;
}
public RequestQueue(Cache cache, Network network, int threadPoolSize) {
this(cache, network, threadPoolSize,
//ResponseDelivery是一個(gè)接口骇钦,實(shí)現(xiàn)類是ExecutorDelivery
new ExecutorDelivery(new Handler(Looper.getMainLooper())));
}
public RequestQueue(Cache cache, Network network) {
this(cache, network, DEFAULT_NETWORK_THREAD_POOL_SIZE);
}
可以看到鳍烁,把傳遞過(guò)來(lái)的cache和network作為變量傳遞給了四個(gè)參數(shù)的構(gòu)造器,在這里,初始化了RequestQueue的幾個(gè)成員變量:mCache(文件緩存)君编、mNetwork(BasicNetwork實(shí)例)、mDispatchers(網(wǎng)絡(luò)請(qǐng)求線程數(shù)組)力崇、以及mDelivery(派發(fā)請(qǐng)求結(jié)果的接口)贞岭,具體意義可看上面的注解。
⌒谥摇(3)構(gòu)造完RequestQueue后犬庇,從(1)可知,最后調(diào)用了它的start()方法,我們來(lái)看看這個(gè)方法,RequestQueue#start():
public void start() {
stop(); // Make sure any currently running dispatchers are stopped.
// Create the cache dispatcher and start it.
mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery);
mCacheDispatcher.start();
// Create network dispatchers (and corresponding threads) up to the pool size.
for (int i = 0; i < mDispatchers.length; i++) {
NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork,
mCache, mDelivery);
mDispatchers[i] = networkDispatcher;
networkDispatcher.start();
}
}
首先實(shí)例化了CacheDispatcher,CacheDispatcher類繼承自Thread,接著調(diào)用了它的start()方法胞锰,開(kāi)始了一條新的緩存線程澎办。接著是一個(gè)for循環(huán)澎羞,根據(jù)設(shè)置的mDispatchers數(shù)組大小來(lái)開(kāi)啟多個(gè)網(wǎng)絡(luò)請(qǐng)求線程僵闯,默認(rèn)是4條網(wǎng)絡(luò)請(qǐng)求線程航攒。
到目前為止庆杜,Volley.newRequestQueue()方法完成了,即我們的網(wǎng)絡(luò)請(qǐng)求第一步公你,建立請(qǐng)求隊(duì)列完成益兄。
先小結(jié)一下:建立請(qǐng)求隊(duì)列所做的工作是古今,創(chuàng)建文件緩存(默認(rèn))抵碟,實(shí)例化BasicNetwork苦囱,實(shí)例化Delivery用于發(fā)送線程請(qǐng)求撼唾,創(chuàng)建一條緩存線程和四條網(wǎng)絡(luò)請(qǐng)求線程(默認(rèn))并運(yùn)行诺苹。
Part 2.網(wǎng)絡(luò)請(qǐng)求的實(shí)現(xiàn)原理
在創(chuàng)建完請(qǐng)求隊(duì)列后,接著就是建立一個(gè)請(qǐng)求雹拄,請(qǐng)求的方式可以是StringRequest收奔、JsonArrayRequest或者ImageRequest等,那么這些請(qǐng)求的背后原理是什么呢滓玖?我們拿最簡(jiǎn)單的StringRequest來(lái)說(shuō)坪哄,它繼承自Request,而Request則是所有請(qǐng)求的父類势篡,所以說(shuō)如果你要自定義一個(gè)網(wǎng)絡(luò)請(qǐng)求翩肌,就應(yīng)該繼承自Request。接下來(lái)我們看看StringRequest的源碼禁悠,因?yàn)椴还躌equest的子類是什么念祭,大體的實(shí)現(xiàn)思路都是一致的,所以我們弄懂了StringRequest绷蹲,那么對(duì)于其他的請(qǐng)求類的理解是相通的棒卷。如下是StringRequest源碼:
public class StringRequest extends Request<String> {
private Listener<String> mListener;
public StringRequest(int method, String url, Listener<String> listener,
ErrorListener errorListener) {
super(method, url, errorListener);
mListener = listener;
}
...
@Override
protected void deliverResponse(String response) {
if (mListener != null) {
mListener.onResponse(response);
}
}
@Override
protected Response<String> parseNetworkResponse(NetworkResponse response) {
String parsed;
try {
parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
} catch (UnsupportedEncodingException e) {
parsed = new String(response.data);
}
return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response));
}
}
源碼并不長(zhǎng)顾孽,我們主要關(guān)注的是deliverResponse方法和parseNetworkResponse祝钢”裙妫可以看出,這兩個(gè)方法都是重寫(xiě)的拦英,我們翻看父類Request的對(duì)應(yīng)方法蜒什,發(fā)現(xiàn)是抽象方法,說(shuō)明這兩個(gè)方法在每一個(gè)自定義的Request中都必須重寫(xiě)疤估。這里簡(jiǎn)單說(shuō)說(shuō)這兩個(gè)方法的作用。先看deliverResponse方法:它內(nèi)部調(diào)用了mListener.onResponse(response)方法,而這個(gè)方法正是我們?cè)趯?xiě)一個(gè)請(qǐng)求的時(shí)候妒貌,添加的listener所重寫(xiě)的onResponse方法俩垃,也就是說(shuō),響應(yīng)成功后在這里調(diào)用了onResponse()方法慷荔。接著看pareNetworkResponse方法雕什,可以看出這里主要是對(duì)response響應(yīng)做出一些處理∠跃В可以對(duì)比一下不同請(qǐng)求類的這個(gè)方法贷岸,都會(huì)不同的,所以說(shuō)磷雇,這個(gè)方法是針對(duì)不同的請(qǐng)求類型而對(duì)響應(yīng)做出不同的處理偿警。比如說(shuō),如果是StringRequest唯笙,則將響應(yīng)包裝成String類型螟蒸;如果是JsonObjectRequest,則將響應(yīng)包裝成JsonObject崩掘。那么現(xiàn)在應(yīng)該清楚了:對(duì)于想要得到某一種特殊類型的請(qǐng)求尿庐,我們可以自定義一個(gè)Request,重寫(xiě)這兩個(gè)方法即可呢堰。
這里小結(jié)一下:Request類做的工作主要是初始化一些參數(shù)抄瑟,比如說(shuō)請(qǐng)求類型、請(qǐng)求的url枉疼、錯(cuò)誤的回調(diào)方法皮假;而它的任一子類重寫(xiě)deliverResponse方法來(lái)實(shí)現(xiàn)成功的回調(diào),重寫(xiě)parseNetworkResponse()方法來(lái)處理響應(yīng)數(shù)據(jù)骂维;至此惹资,一個(gè)完整的Request請(qǐng)求搭建完畢。
Part 3.添加請(qǐng)求
前面已經(jīng)完成了請(qǐng)求隊(duì)列的創(chuàng)建航闺,Request請(qǐng)求的創(chuàng)建褪测,那么接下來(lái)就是把請(qǐng)求添加進(jìn)隊(duì)列了猴誊。我們看RequestQueue#add()源碼:
/**
* Adds a Request to the dispatch queue.
* @param request The request to service
* @return The passed-in request
*/
public <T> Request<T> add(Request<T> request) {
// Tag the request as belonging to this queue and add it to the set of current requests.
//標(biāo)記當(dāng)前請(qǐng)求,表示這個(gè)請(qǐng)求由當(dāng)前RequestQueue處理
request.setRequestQueue(this);
synchronized (mCurrentRequests) {
mCurrentRequests.add(request);
}
// Process requests in the order they are added.
//獲得當(dāng)前請(qǐng)求的序號(hào)
request.setSequence(getSequenceNumber());
request.addMarker("add-to-queue");
// If the request is uncacheable, skip the cache queue and go straight to the network.
//如果請(qǐng)求不能緩存侮措,直接添加到網(wǎng)絡(luò)請(qǐng)求隊(duì)列懈叹,默認(rèn)是可以緩存
if (!request.shouldCache()) {
mNetworkQueue.add(request);
return request;
}
// Insert request into stage if there's already a request with the same cache key in flight.
// 鎖定當(dāng)前代碼塊,只能一條線程執(zhí)行
synchronized (mWaitingRequests) {
String cacheKey = request.getCacheKey();
//是否有相同請(qǐng)求正在處理
if (mWaitingRequests.containsKey(cacheKey)) {
// There is already a request in flight. Queue up.
//如果有相同請(qǐng)求正在處理分扎,那么把這個(gè)請(qǐng)求放進(jìn)mWaitingRequest中澄成,等待。
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.
//沒(méi)有相同的請(qǐng)求畏吓,那么把請(qǐng)求放進(jìn)mWaitingRequests中墨状,同時(shí)也放進(jìn)mCacheQueue緩存隊(duì)列中
//這代表這個(gè)請(qǐng)求已經(jīng)開(kāi)始在緩存線程中運(yùn)行了
mWaitingRequests.put(cacheKey, null);
mCacheQueue.add(request);
}
return request;
}
}
結(jié)合相應(yīng)的注釋,我們得出如下結(jié)論:在這個(gè)add方法中菲饼,主要判斷一個(gè)Request請(qǐng)求是否可以緩存(默認(rèn)是可以緩存的)肾砂,如果不可以則直接添加到網(wǎng)絡(luò)請(qǐng)求隊(duì)列開(kāi)始網(wǎng)絡(luò)通信;如果可以宏悦,則進(jìn)一步判斷當(dāng)前是否有相同的請(qǐng)求正在進(jìn)行镐确,如果有相同的請(qǐng)求,則讓這個(gè)請(qǐng)求排隊(duì)等待肛根,如果沒(méi)有相同的請(qǐng)求辫塌,則直接放進(jìn)緩存隊(duì)列中。如果對(duì)此還有什么疑問(wèn)派哲,可以看下面的流程圖(圖片來(lái)自網(wǎng)絡(luò)):
Part 4.緩存線程
在part1的最后實(shí)例化了緩存線程并開(kāi)始運(yùn)行臼氨,一直處于等待狀態(tài),而上面把請(qǐng)求添加進(jìn)了緩存線程芭届,此時(shí)緩存線程就開(kāi)始真正的工作了储矩。我們來(lái)看緩存線程的源碼,主要看它的run()方法褂乍,CacheDispatcher#run():
@Override
public void run() {
if (DEBUG) VolleyLog.v("start new dispatcher");
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
// Make a blocking call to initialize the cache.
mCache.initialize();
Request<?> request;
while (true) {
// release previous request object to avoid leaking request object when mQueue is drained.
request = null;
try {
// Take a request from the queue.
//從緩存隊(duì)列中取出請(qǐng)求
request = mCacheQueue.take();
} ...
try {
request.addMarker("cache-queue-take");
// If the request has been canceled, don't bother dispatching it.
if (request.isCanceled()) {
request.finish("cache-discard-canceled");
continue;
}
// Attempt to retrieve this item from cache.
//從文件緩存中取出這個(gè)請(qǐng)求的結(jié)果
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.
//判斷緩存是否過(guò)期
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");
//先將響應(yīng)的結(jié)果包裝成NetworkResponse持隧,然后調(diào)用Request子類的
//parseNetworkResponse方法解析數(shù)據(jù)
Response<?> response = request.parseNetworkResponse(
new NetworkResponse(entry.data, entry.responseHeaders));
request.addMarker("cache-hit-parsed");
if (!entry.refreshNeeded()) {
// Completely unexpired cache hit. Just deliver the response.
//調(diào)用ExecutorDelivey#postResponse方法
mDelivery.postResponse(request, response);
} else {
....
}
} catch (Exception e) {
VolleyLog.e(e, "Unhandled exception %s", e.toString());
}
}
}
在run()方法中,我們可以看到最開(kāi)始有一個(gè)while(true)循環(huán)逃片,表示它一直在等待緩存隊(duì)列的新請(qǐng)求的出現(xiàn)屡拨。接著,先判斷這個(gè)請(qǐng)求是否有對(duì)應(yīng)的緩存結(jié)果褥实,如果沒(méi)有則直接添加到網(wǎng)絡(luò)請(qǐng)求隊(duì)列呀狼;接著再判斷這個(gè)緩存結(jié)果是否過(guò)期了,如果過(guò)期則同樣地添加到網(wǎng)絡(luò)請(qǐng)求隊(duì)列损离;接下來(lái)便是對(duì)緩存結(jié)果的處理了哥艇,我們可以看到,先是把緩存結(jié)果包裝成NetworkResponse類僻澎,然后調(diào)用了Request的parseNetworkResponse貌踏,這個(gè)方法我們?cè)趐art2說(shuō)過(guò)十饥,子類需要重寫(xiě)這個(gè)方法來(lái)處理響應(yīng)數(shù)據(jù)。最后祖乳,把處理好的數(shù)據(jù)post到主線程逗堵,這里用到了ExecutorDelivery#postResponse()方法,下面會(huì)分析到凡资。
小結(jié):CacheDispatcher線程主要對(duì)請(qǐng)求進(jìn)行判斷砸捏,是否已經(jīng)有緩存谬运,是否已經(jīng)過(guò)期隙赁,根據(jù)需要放進(jìn)網(wǎng)絡(luò)請(qǐng)求隊(duì)列。同時(shí)對(duì)相應(yīng)結(jié)果進(jìn)行包裝梆暖、處理伞访,然后交由ExecutorDelivery處理。這里以一張流程圖顯示它的完整工作流程:
Part 5.網(wǎng)絡(luò)請(qǐng)求線程
上面提到轰驳,請(qǐng)求不能緩存厚掷、緩存結(jié)果不存在、緩存過(guò)期的時(shí)候會(huì)把請(qǐng)求添加進(jìn)請(qǐng)求隊(duì)列级解,此時(shí)一直等待的網(wǎng)絡(luò)請(qǐng)求線程由于獲取到請(qǐng)求冒黑,終于要開(kāi)始工作了,我們來(lái)看NetworkDispatcher#run()方法:
@Override
public void run() {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
Request<?> request;
while (true) {
long startTimeMs = SystemClock.elapsedRealtime();
// release previous request object to avoid leaking request object when mQueue is drained.
request = null;
try {
// Take a request from the queue.
request = mQueue.take();
} ...
try {
...
// Perform the network request.
//調(diào)用BasicNetwork實(shí)現(xiàn)類進(jìn)行網(wǎng)絡(luò)請(qǐng)求勤哗,并獲得響應(yīng) 1
NetworkResponse networkResponse = mNetwork.performRequest(request);
...
// Parse the response here on the worker thread.
//對(duì)響應(yīng)進(jìn)行解析
Response<?> response = request.parseNetworkResponse(networkResponse);
request.addMarker("network-parse-complete");
...
request.markDelivered();
mDelivery.postResponse(request, response);
// Write to cache if applicable.
//將響應(yīng)結(jié)果寫(xiě)進(jìn)緩存
if (request.shouldCache() && response.cacheEntry != null) {
mCache.put(request.getCacheKey(), response.cacheEntry);
request.addMarker("network-cache-written");
}
} ...
}
}
源碼做了適當(dāng)?shù)膭h減抡爹,大體上和CacheDispatcher的邏輯相同,這里關(guān)注①號(hào)代碼芒划,這里調(diào)用了BasicNetwork#perfromRequest()方法冬竟,把請(qǐng)求傳遞進(jìn)去,可以猜測(cè)民逼,這個(gè)方法內(nèi)部實(shí)現(xiàn)了網(wǎng)絡(luò)請(qǐng)求的相關(guān)操作泵殴,那么我們進(jìn)去看看,BasicNetwork#perfromRequest():
@Override
public NetworkResponse performRequest(Request<?> request) throws VolleyError {
long requestStart = SystemClock.elapsedRealtime();
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());
httpResponse = mHttpStack.performRequest(request, headers); // 1
StatusLine statusLine = httpResponse.getStatusLine();
int statusCode = statusLine.getStatusCode();
responseHeaders = convertHeaders(httpResponse.getAllHeaders());
// Handle cache validation.
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); // 2
}
// A HTTP 304 response does not have all header fields. We
// have to use the header fields from the cache entry plus
// the new ones from the response.
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.5
entry.responseHeaders.putAll(responseHeaders);
return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED, entry.data,
entry.responseHeaders, true,
SystemClock.elapsedRealtime() - requestStart);
}
...
}
}
我們主要看①號(hào)代碼拼苍,mHttpStack.performRequest();這里調(diào)用了mHttpStack的performRequest方法笑诅,那么mHttpStack是什么呢?我們可以翻上去看看part1處實(shí)例化BasicNetwork的時(shí)候傳遞的stack值疮鲫,該值就是根據(jù)不同的系統(tǒng)版本號(hào)而實(shí)例化的HttpStack對(duì)象(版本號(hào)大于9的是HurlStack吆你,小于9的是HttpClientStack),由此可知棚点,這里實(shí)際調(diào)用的是HurlStack.performRequest()方法早处,方法的內(nèi)部基本是關(guān)于HttpUrlConnection的邏輯代碼,這里就不展開(kāi)說(shuō)了瘫析∑霭穑可以這么說(shuō):HurlStack封裝好了HttpUrlConnection默责,而HttpClientStack封裝了HttpClient。該方法返回了httpResponse咸包,接著把這個(gè)響應(yīng)交由②處處理桃序,封裝成NetworkResponse對(duì)象并返回。在NetworkDispatcher#run()方法獲取返回的NetworkResponse對(duì)象后烂瘫,對(duì)響應(yīng)解析媒熊,通過(guò)ExecutorDelivery#postResponse()方法回調(diào)解析出來(lái)的數(shù)據(jù),這個(gè)過(guò)程和CacheDispatcher相同坟比。
Part 6.ExecutorDelivery 通知主線程
在CacheDispatcher和NetworkDispatcher中最后都有調(diào)用到ExecutorDelivery#postResponse()方法芦鳍,那么這個(gè)方法到底是做什么呢?由于緩存線程和網(wǎng)絡(luò)請(qǐng)求線程都不是主線程葛账,所以主線程需要有“人”通知它網(wǎng)絡(luò)請(qǐng)求已經(jīng)完成了柠衅,而這個(gè)“人”正是由ExecutorDelivery充當(dāng)。在完成請(qǐng)求后籍琳,通過(guò)ExecutorDelivery#postResponse()方法菲宴,最終會(huì)回調(diào)到主線程中重寫(xiě)的onResponse()方法。我們看看這個(gè)方法的源碼ExecutorDelivery#postResponse():
@Override
public void postResponse(Request<?> request, Response<?> response) {
postResponse(request, response, null);
}
@Override
public void postResponse(Request<?> request, Response<?> response, Runnable runnable) {
request.markDelivered();
request.addMarker("post-response");
mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, runnable));
}
在方法內(nèi)部調(diào)用了mResponsePoster#execute()方法趋急,那么喝峦,這個(gè)mResponsePoster是在哪里來(lái)的呢?其實(shí)這個(gè)成員變量是在ExecutorDelivery實(shí)例化的時(shí)候同時(shí)實(shí)例化的呜达,而ExecutorDelivery則是在RequestQueue實(shí)例化的時(shí)候同時(shí)實(shí)例化的谣蠢,讀者可以自行查看相應(yīng)的構(gòu)造方法,其實(shí)這些工作在par 1建立請(qǐng)求隊(duì)列的時(shí)候已經(jīng)全部做好了闻丑。接著我們可以看以下代碼漩怎,ExecutorDelivery#ExecutorDelivery():
public ExecutorDelivery(final Handler handler) {
// Make an Executor that just wraps the handler.
//實(shí)例化Executor,并且重寫(xiě)execute方法
mResponsePoster = new Executor() {
@Override
public void execute(Runnable command) {
//這里獲取的handler是主線程的handler嗦嗡,可看part 1 (2)
handler.post(command);
}
};
}
execute()方法接收一個(gè)Runnable對(duì)象勋锤,那么我們回到上面的
mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, runnable));
可以看出這里實(shí)例化了一個(gè)ResponseDeliveryRunnable對(duì)象作為Runnable對(duì)象。而這里的ResponseDeliveryRunnable則是當(dāng)前類Executor的一個(gè)內(nèi)部類侥祭,實(shí)現(xiàn)了Runnable接口叁执,我們來(lái)看看:
/**
* 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;
//構(gòu)造方法
...
@Override
public void run() {
// If this request has canceled, finish it and don't deliver.
if (mRequest.isCanceled()) {
mRequest.finish("canceled-at-delivery");
return;
}
// Deliver a normal response or error, depending.
if (mResponse.isSuccess()) {
mRequest.deliverResponse(mResponse.result); // 1
} else {
mRequest.deliverError(mResponse.error);
}
...
}
}
}
在上面,①號(hào)代碼回調(diào)到了Request的deliverResponse方法矮冬,即此時(shí)通知了主線程谈宛,請(qǐng)求已經(jīng)完成,此時(shí)在Request子類重寫(xiě)的deliverResponse方法則會(huì)調(diào)用onResponse()方法胎署,那么我們的Activity就能方便調(diào)用解析好的請(qǐng)求結(jié)果了吆录。
到目前為止,關(guān)于Volley的源碼解析完畢琼牧。
總結(jié)
用google官方的一幅圖來(lái)說(shuō)明以上所說(shuō)各個(gè)部分的關(guān)系(圖片來(lái)自網(wǎng)絡(luò)):
藍(lán)色部分代表主線程恢筝,綠色部分代表緩存線程哀卫,橙色部分代表網(wǎng)絡(luò)請(qǐng)求線程。讀者可以根據(jù)這幅圖所展示的關(guān)系撬槽,再仔細(xì)體會(huì)part 1-6所說(shuō)的流程此改,那么就很容易理解了。最后感謝你的閱讀侄柔。