文章摘要
1秘血、volley 中的工作線程
2即彪、volley 工作步驟
3紧唱、RequestQueue初始化以及初始化邏輯
附:獲取Volley源代碼
Demos案例源碼:https://github.com/HailouWang/DemosForApi
感悟:
Volley的源代碼真的值得去讀,其中包含了很多非常好的處理邏輯隶校,例如:Volley對其工作流程的架構(gòu)漏益、線程緩存的處理、網(wǎng)絡(luò)請求數(shù)據(jù)的解析以及處理深胳、其中用到的設(shè)計模式等绰疤。
當(dāng)我們明確了volley要解決的開發(fā)痛點后,volley提供了松耦合的架構(gòu)實現(xiàn)舞终,我們可以很方便的在其框架實現(xiàn)內(nèi)轻庆,為其進(jìn)行功能擴(kuò)展。引用設(shè)計模式的一句話:一切為了松耦合的設(shè)計而努力敛劝。
簡介:
volley有兩個主要的民工余爆,CacheDispatcher以及NetworkDispatcher,也是兩個線程夸盟,管理并處理Request任務(wù)蛾方。
volley為了保證大批量的網(wǎng)絡(luò)請求以及數(shù)據(jù)解析不會影響到主線程的用戶交互,使用了很多線程以及線程封裝技巧。包括這里的Cache桩砰。
在用戶發(fā)起網(wǎng)絡(luò)請求后拓春,volley就將用戶的請求,丟到了本文介紹的緩存進(jìn)程亚隅,緩存線程如果沒有能力處理硼莽,就丟給網(wǎng)絡(luò)線程,并告訴它煮纵,老大需要數(shù)據(jù)結(jié)果懂鸵,你趕緊去網(wǎng)絡(luò)上去拿。老大只要結(jié)果醉途,不要過程矾瑰。
主線程很忙,ResponseDelivery負(fù)責(zé)傳遞消息隘擎,伴君如伴虎殴穴,為了防止打擾到主線程的工作,ResponseDelivery也可以有一個線程货葬,在目前的源碼里采幌,ResponseDelivery充分利用Handler的MessageQueue優(yōu)勢,管理并小心的將結(jié)果傳遞給主線程震桶。
1休傍、volley 中,存在三類線程:
- 1蹲姐、主線程磨取。將獲取的數(shù)據(jù)刷新到UI,發(fā)送網(wǎng)絡(luò)請求等柴墩。
- 2忙厌、緩存進(jìn)程(Cache Thread)。管理緩存數(shù)據(jù)江咳,主線程的請求逢净,優(yōu)先從主線程中獲取數(shù)據(jù),其次將請求分發(fā)到網(wǎng)絡(luò)中歼指。
- 3爹土、網(wǎng)絡(luò)線程(Network Thread)。用戶可以制定網(wǎng)絡(luò)線程的數(shù)量踩身,默認(rèn)是4個胀茵。定義了從網(wǎng)絡(luò)獲取數(shù)據(jù)的流程,但不包括網(wǎng)絡(luò)同步邏輯挟阻。這樣子的設(shè)計宰掉,可以更好的釋放線程和網(wǎng)絡(luò)解析邏輯之間的耦合呵哨。
for (int i = 0; i < DEFAULT_NETWORK_THREAD_POOL_SIZE; i++) {
NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork,
mCache, mDelivery);
mDispatchers[i] = networkDispatcher;
networkDispatcher.start();
}
2、volley 工作步驟
之前的Demos中發(fā)送一個簡單的請求轨奄、,無論是通過RequestQueue還是通過ImageLoader拒炎,大致的使用步驟是一樣的挪拟,大體包括以下步驟:
- 2.1、初始化RequestQueue或者ImageLoader击你。
// Instantiate the RequestQueue.
RequestQueue queue = Volley.newRequestQueue(this);
String url ="http://www.google.com";
- 2.2玉组、初始化Request
// Request a string response from the provided URL.
StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
new Response.Listener<String>() {
@Override
public void onResponse(String response) {
// Display the first 500 characters of the response string.
mTextView.setText("Response is: "+ response.substring(0,500));
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
mTextView.setText("That didn't work!");
}
});
- 2.3、 將Request 加入到RequestQueue丁侄。
// Add the request to the RequestQueue.
queue.add(stringRequest);
后兩個步驟惯雳,是對RequestQueue的使用,所以鸿摇,我們將重點放在第一部分石景,即:RequestQueue的創(chuàng)建流程。
3拙吉、RequestQueue初始化
RequestQueue會對Request進(jìn)行管理潮孽,它的作用,更多的是作為一個工具類筷黔,通過add方法往史,將Request分發(fā)給Cache線程以及網(wǎng)絡(luò)線程。
- 3.1佛舱、首先通過newRequestQueue方法獲得RequestQueue對象椎例。
public static RequestQueue newRequestQueue(Context context) {
//1、初始化Network對象请祖。Network的意義是通過performRequest方法解析Request订歪,生成Response對象。
HttpStack stack;
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));
}
}
Network network = new BasicNetwork(stack);
//2损拢、初始化RequestQueue陌粹,共計兩個參數(shù):第一個參數(shù)是Cache緩沖區(qū),可選福压,即:可不緩沖掏秩。
//第二個參數(shù)是network對象,也是關(guān)系解析網(wǎng)絡(luò)數(shù)據(jù)的主要勞工荆姆。
RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir), network);
queue.start();
return queue;
}
- 3.2蒙幻、RequestQueue的實例初始化,調(diào)用start后胆筒,線程會跑起來邮破。
/**
* Creates the worker pool. Processing will not begin until {@link #start()} is called.
*創(chuàng)建一個工作池诈豌,非start方法調(diào)用前,不會開始執(zhí)行
* @param cache A Cache to use for persisting responses to disk
* 1抒和、緩存者矫渔。將相應(yīng)數(shù)據(jù)持久化到硬盤
* @param network A Network interface for performing HTTP requests
* 2、網(wǎng)絡(luò)處理者摧莽。處理HTTP請求的Network 接口
* @param threadPoolSize Number of network dispatcher threads to create
* 3庙洼、網(wǎng)絡(luò)請求分發(fā)者。默認(rèn)4個分發(fā)線程池
* @param delivery A ResponseDelivery interface for posting responses and errors
* 4镊辕、響應(yīng)傳遞者油够。運行在主線程,傳遞響應(yīng)數(shù)據(jù)征懈,以及錯誤日志信息石咬,實現(xiàn)來自:Handler的封裝
*/
public RequestQueue(Cache cache, Network network, int threadPoolSize,
ResponseDelivery delivery) {
mCache = cache;
mNetwork = network;
mDispatchers = new NetworkDispatcher[threadPoolSize];
mDelivery = delivery;
}
4、RequestQueue將Request拋給工作線程
RequestQueue通過add方法卖哎,將Request拋給工作線程鬼悠,工作線程包含我們上面說的Cache線程、Network線程棉饶。
//1厦章、將Request加入到mCurrentRequests,因為本工具類還需要管理Request照藻,例如:cancel等袜啃。
// Tag the request as belonging to this queue and add it to the set of current requests.
request.setRequestQueue(this);
synchronized (mCurrentRequests) {
mCurrentRequests.add(request);
}
// Process requests in the order they are added.
//2、包裝Request幸缕。為其賦予SequenceNumber
request.setSequence(getSequenceNumber());
request.addMarker("add-to-queue");
// If the request is uncacheable, skip the cache queue and go straight to the network.
//3群发、如果Request不需要緩存,則直接加入到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.
//4发乔、如果請求(Request)不是在等待中(即:mWaitingRequests中)熟妓,那么就先拋給緩沖線程(mCacheQueue)。
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<>();
}
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);
}
緩沖區(qū)(RequestQueue)在獲得Request后栏尚,接著如何處理起愈,請關(guān)注:volley 源碼解析之緩存線程工作流程