以StringRequest為例子,分析Volley是怎樣執(zhí)行一個(gè)網(wǎng)絡(luò)請(qǐng)求的某残。
先看實(shí)現(xiàn)Request抽象類的StringRequest
public class StringRequest extends Request<String> {
private Listener<String> mListener;
/**
* Creates a new request with the given method.
*
* @param method the request {@link Method} to use
* @param url URL to fetch the string at
* @param listener Listener to receive the String response
* @param errorListener Error listener, or null to ignore errors
*/
public StringRequest(int method, String url, Listener<String> listener,
ErrorListener errorListener) {
super(method, url, errorListener);
mListener = listener;
}
}
Request有3個(gè)參數(shù):
- method 對(duì)應(yīng)請(qǐng)求的方式
- url 請(qǐng)求的地址
- errorListener 發(fā)生錯(cuò)誤時(shí)回調(diào)
StringRequest多了一個(gè)自己的listener作為成功請(qǐng)求的回調(diào)接口驮俗。
StringRequest實(shí)現(xiàn)了parseNetworkResponse方法。這個(gè)方法會(huì)傳入一個(gè)NetworkResponse對(duì)象,包裝了請(qǐng)求的響應(yīng)結(jié)果琳状。
然后根據(jù)響應(yīng)結(jié)結(jié)果header里的編碼格式構(gòu)造一個(gè)String對(duì)象,最后使用封裝了最終請(qǐng)求的Response類構(gòu)造一個(gè)代表成功的response返回硝桩。
@Override
protected Response<String> parseNetworkResponse(NetworkResponse response) {
String parsed;
try {
//根據(jù)編碼格式構(gòu)造字符串
parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
} catch (UnsupportedEncodingException e) {
//如果格式不支持編碼沿猜,就構(gòu)造一個(gè)默認(rèn)的UTF-8編碼的字符串
parsed = new String(response.data);
}
return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response));
}
NetworkResponse封裝了具體的請(qǐng)求內(nèi)容:
public class NetworkResponse implements Serializable{
/**
* @param statusCode the HTTP status code
* @param data Response body
* @param headers Headers returned with this response, or null for none
* @param notModified True if the server returned a 304 and the data was already in cache
* @param networkTimeMs Round-trip network time to receive network response
*/
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;
}
}
- StringReqeust 負(fù)責(zé)封裝請(qǐng)求
- NetworkResponse 負(fù)責(zé)封裝從服務(wù)器返回的請(qǐng)求
- Response 負(fù)責(zé)構(gòu)造最終的結(jié)果。
RequestQueue的創(chuàng)建
Volley.newRequestQueue
有幾個(gè)重載方法碗脊,最終都會(huì)執(zhí)行這個(gè):
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) {
}
if (stack == null) {
if (Build.VERSION.SDK_INT >= 9) {
stack = new HurlStack();
} else {
stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));
}
}
Network network = new BasicNetwork(stack);
RequestQueue queue;
if (maxDiskCacheBytes <= -1){
queue = new RequestQueue(new DiskBasedCache(cacheDir), network);
}
else{
queue = new RequestQueue(new DiskBasedCache(cacheDir, maxDiskCacheBytes), network);
}
queue.start();
return queue;
}
其中執(zhí)行了一些對(duì)象的創(chuàng)建工作:
- 創(chuàng)建緩存文件啼肩,文件名默認(rèn)為
volley
- 創(chuàng)建一個(gè)
UserAgent
字符串,代表HTTP頭里的客戶端身份衙伶。默認(rèn)為包名+APPb版本號(hào)祈坠。 - 創(chuàng)建執(zhí)行網(wǎng)絡(luò)請(qǐng)求的工具。
HurlStack
(Android 2.3及以上)或HttpClientStack
(Android 2.3以下)矢劲。Stack負(fù)責(zé)真正的HTTP請(qǐng)求赦拘。HurlStack
使用的是HttpURLConnection
;HttpClientStack
使用的是HttpClient
。 - 創(chuàng)建一個(gè)
Netwoker
對(duì)象芬沉。Netwoker
通過調(diào)用Stack
進(jìn)行網(wǎng)絡(luò)訪問躺同,并將執(zhí)行結(jié)果封裝為NetworkResponse
對(duì)象。 - 創(chuàng)建一個(gè)
RequestQueue
對(duì)象丸逸,同時(shí)創(chuàng)建一個(gè)DiskBasedCache
緩存對(duì)象蹋艺,作為本地緩存。 - RequestQueue創(chuàng)建完畢之后椭员,就調(diào)用
queue.start()
開始不斷執(zhí)行添加到RequestQueue中的請(qǐng)求车海。
RequestQueue的創(chuàng)建:
RequestQueue有3個(gè)構(gòu)造函數(shù):
//最終調(diào)用
public RequestQueue(Cache cache, Network network, int threadPoolSize,
ResponseDelivery delivery) {
mCache = cache;
mNetwork = network;
mDispatchers = new NetworkDispatcher[threadPoolSize];
mDelivery = delivery;
}
public RequestQueue(Cache cache, Network network, int threadPoolSize) {
//會(huì)調(diào)用最終的構(gòu)造函數(shù)
this(cache, network, threadPoolSize,
new ExecutorDelivery(new Handler(Looper.getMainLooper())));
}
public RequestQueue(Cache cache, Network network) {
//會(huì)調(diào)用第二個(gè)
this(cache, network, DEFAULT_NETWORK_THREAD_POOL_SIZE);
}
三個(gè)構(gòu)造函數(shù)最終都是調(diào)用最上面那個(gè)。第二個(gè)構(gòu)造函數(shù)隘击,則是創(chuàng)建了一個(gè)ExecutorDelivery
對(duì)象侍芝,并在創(chuàng)建時(shí)傳入了擁有UI線程的handler
。
可見ExecutorDelivery
是與主線程打交道的工具埋同。
最后一個(gè)構(gòu)造函數(shù)州叠,則創(chuàng)建了:
- 一個(gè)
NetworkDispatcher
數(shù)組,數(shù)組大小為threadPoolSize
凶赁,默認(rèn)為4咧栗。
NetworkDispatcher
NetworkDispatcher繼承Thread。RequestQueue在創(chuàng)建時(shí)虱肄,創(chuàng)建了一個(gè)NetworkDispatcher數(shù)組致板,實(shí)際就是創(chuàng)建了一個(gè)線程數(shù)組。
public class NetworkDispatcher extends Thread {
/** The queue of requests to service. */
private final BlockingQueue<Request<?>> mQueue;
/** The network interface for processing requests. */
private final Network mNetwork;
/** The cache to write to. */
private final Cache mCache;
/** For posting responses and errors. */
private final ResponseDelivery mDelivery;
/** Used for telling us to die. */
private volatile boolean mQuit = false;
}
NetworkDispatcher擁有:
- BlockingQueue<Request<?>> 一個(gè)保存者Request的阻塞隊(duì)列
- Network 執(zhí)行網(wǎng)絡(luò)訪問咏窿,并返回結(jié)果
- Cache 本地緩存
- ResponseDelivery 負(fù)責(zé)與UI線程打交道斟或。ReqeustQueue在創(chuàng)建時(shí),創(chuàng)建的ExecutorDelivery就是一個(gè)實(shí)現(xiàn)了ResponseDelivery接口的類集嵌。
- volatile boolen mQuit 一個(gè)多線程可以安全訪問的布爾萝挤,負(fù)責(zé)結(jié)束線程
NetworkDispatcher既然繼承自Thread御毅,那么就實(shí)現(xiàn)了run方法:
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();
} 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);
// Perform the network request.
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");
// Write to cache if applicable.
// TODO: Only update cache metadata instead of entire record for 304s.
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);
} 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);
}
}
}
- 設(shè)置當(dāng)前線程的優(yōu)先級(jí)為后臺(tái)線程
- 從阻塞隊(duì)列中獲取一個(gè)request請(qǐng)求。這里使用的
take
方法怜珍,這個(gè)方法會(huì)阻塞線程端蛆,直到線程從隊(duì)列中拿到了東西。 - 給request添加
network-queue-take
標(biāo)記 - 調(diào)用netwoke的
performRequest
方法酥泛,并傳入requset
獲取請(qǐng)求的結(jié)果networkResponse - 給request添加
network-http-complete
標(biāo)記 - 通過response判斷是否是
304
狀態(tài)碼今豆,如果是就調(diào)用request.finish()
,并跳過下面步驟揭璃。否則繼續(xù)下面的步驟晚凿。 - 使用
request.parseNetworkResponse(networkResponse);
創(chuàng)建一個(gè)Response
對(duì)象response - 給request添加
network-parse-complete
標(biāo)記 - 將請(qǐng)求
requset
和結(jié)果response
寫入緩存。 - 調(diào)用
request.markDelivered();
表明瘦馍,當(dāng)前請(qǐng)求已被解決 - 調(diào)用
mDelivery.postResponse(request, response);
將請(qǐng)求和結(jié)果傳遞到UI線程歼秽。
這就是一個(gè)
NetworkDispatcher
線程執(zhí)行一個(gè)Request
的大致流程。
ResponseDelivery->ExecutorDelivery
在NetworkDispatcher
線程中情组,最終結(jié)果是通過mDeliery
這個(gè)ResponseDelivery
對(duì)象傳遞到UI線程的燥筷。在創(chuàng)建NetworkDispatcher
時(shí),mDeliery
被賦予的實(shí)際是ExecutorDelivery
的實(shí)例院崇。ExecutorDelivery
是ResponseDelivery
接口的實(shí)現(xiàn)類肆氓。
ExecutorDelivery類的postResponse
方法:
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));
}
postResponse 方法調(diào)用了 mResponsePoster
的execute()
方法,并傳入了一個(gè)Runnable
對(duì)象底瓣。
mResponsePoster 對(duì)象是一個(gè) Executor
對(duì)象谢揪,并在 ExecutorDelivery 并創(chuàng)建時(shí)就創(chuàng)建。它的execute
方法捐凭,就是調(diào)用 RequestQueue在創(chuàng)建 ExecutorDelivery 傳入的擁有UI線程的Looper的handler
的post(Runnable)
方法拨扶。
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);
}
};
}
handler post 的runnable對(duì)象是一個(gè)內(nèi)部類:在 run 方法里調(diào)用了Request
對(duì)象的deliverResponse
deliverError
finish
方法。
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;
}
// Deliver a normal response or error, depending.
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();
}
}
}
經(jīng)過這樣的轉(zhuǎn)化茁肠,相當(dāng)于Request
的幾個(gè)方法就是在UI線程執(zhí)行了:
//Requset自己實(shí)現(xiàn)的deliverError
public void deliverError(VolleyError error) {
if (mErrorListener != null) {
mErrorListener.onErrorResponse(error);
}
}
//StringRequest實(shí)現(xiàn)的Request的抽象方法deliverResponse
protected void deliverResponse(String response) {
if (mListener != null) {
mListener.onResponse(response);
}
}
Requset的deliver
方法實(shí)際就是調(diào)用的在創(chuàng)建Request的時(shí)候患民,傳入的Listener接口的方法。
Volley每創(chuàng)建一個(gè)消息隊(duì)列垦梆,就創(chuàng)建了4個(gè)這樣的NetworkDispatcher線程一直從請(qǐng)求隊(duì)列中獲取請(qǐng)求匹颤,然后執(zhí)行,最后post到UI線程托猩。4個(gè)線程都去拿請(qǐng)求印蓖,不會(huì)發(fā)生沖突是因?yàn)檎?qǐng)求放在了BlockingQueue
中,保證了每次take
獲取操作只有一個(gè)線程能獲取京腥。而且Volley的BlockingQueue使用的是PriorityBlockingQueue
另伍,這個(gè)隊(duì)列在擁有BlockingQueue功能的同時(shí),還對(duì)隊(duì)列中的請(qǐng)求進(jìn)行了排序。
add請(qǐng)求操作
RequestQueue中的線程們一直在跑著摆尝,它們不斷的有序的從消息阻塞隊(duì)列中拿請(qǐng)求,執(zhí)行請(qǐng)求因悲,傳遞到UI線程堕汞。
ReqeustQueue的add
操作就是將請(qǐng)求添加到請(qǐng)求隊(duì)列中。
// Process requests in the order they are added.
request.setSequence(getSequenceNumber());
request.addMarker("add-to-queue");
// If the request is uncacheable, skip the cache queue and go straight to the network.
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.
synchronized (mWaitingRequests) {
String cacheKey = request.getCacheKey();
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;
}
- 如果加入的請(qǐng)求沒有被緩存過晃琳,就直接加入到消息隊(duì)列讯检。直接加入不用獲取消息隊(duì)列的鎖。因?yàn)橄㈥?duì)列是個(gè)
BlockingQueue
卫旱,本就支持并發(fā)操作人灼。而且即使add
操作是在UI線程,也不會(huì)阻塞UI線程顾翼,因?yàn)?br>mNetworkQueue.add(request);
內(nèi)部是調(diào)用BlockingQueue
的offer
操作投放,offer
入隊(duì)操作不會(huì)阻塞線程,如果入隊(duì)失敗适贸,它會(huì)返回false
灸芳。
以上只是我分析的Volley的RequestQueue的大概執(zhí)行過程。其中還有
CacheQueue
WaitRequests
CurrentRequests
等一些細(xì)節(jié)和HurlStack和HttpClientStack的網(wǎng)絡(luò)請(qǐng)求部分沒有具體分析拜姿。
如果有哪里不對(duì)的烙样,希望指正。