摘要:接下來看看網(wǎng)絡(luò)調(diào)度線程。讓我們再回到,請求網(wǎng)絡(luò)后,會將響應(yīng)結(jié)果存在緩存中,如果響應(yīng)結(jié)果成功則調(diào)用來回調(diào)給主線程。我們用請求網(wǎng)絡(luò)的寫法是這樣的將請求添加在請求隊列中看到第行整個的大致流程都通了吧,好了關(guān)于的源碼就講到這里。
1.Volley結(jié)構(gòu)圖
從上圖可以看到Volley分為三個線程,分別是主線程、緩存調(diào)度線程、和網(wǎng)絡(luò)調(diào)度線程,首先請求會加入緩存隊列,如果發(fā)現(xiàn)可以找到相應(yīng)的緩存結(jié)果就直接讀取緩存并解析,然后回調(diào)給主線程;如果在緩存中沒有找到結(jié)果,則將這條請求加入到網(wǎng)絡(luò)隊列中,然后發(fā)送HTTP請求,解析響應(yīng)并寫入緩存,并回調(diào)給主線程。
2.從RequestQueue入手我們都知道使用Volley之前首先要創(chuàng)建RequestQueue:
RequestQueue mQueue = Volley.newRequestQueue(getApplicationContext());
這也是volley運作的入口,看看newRequestQueue:
public static RequestQueue newRequestQueue(Context context) { return newRequestQueue(context, (HttpStack)null); } public static RequestQueue newRequestQueue(Context context, HttpStack stack) { return newRequestQueue(context, stack, -1); }
連續(xù)調(diào)用了兩個重載函數(shù),最終調(diào)用的是:
public static RequestQueue newRequestQueue(Context context, HttpStack stack, int maxDiskCacheBytes) { File cacheDir = new File(context.getCacheDir(), "volley"); String userAgent = "volley/0"; try { String network = context.getPackageName(); PackageInfo queue = context.getPackageManager().getPackageInfo(network, 0); userAgent = network + "/" + queue.versionCode; } catch (NameNotFoundException var7) { ; } if(stack == null) { if(VERSION.SDK_INT >= 9) { stack = new HurlStack(); } else { stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent)); } } BasicNetwork network1 = new BasicNetwork((HttpStack)stack); RequestQueue queue1; if(maxDiskCacheBytes <= -1) { queue1 = new RequestQueue(new DiskBasedCache(cacheDir), network1); } else { queue1 = new RequestQueue(new DiskBasedCache(cacheDir, maxDiskCacheBytes), network1); } queue1.start(); return queue1; }
可以看到如果android版本大于等于2.3則調(diào)用基于HttpURLConnection的HurlStack,否則就調(diào)用基于HttpClient的HttpClientStack。并創(chuàng)建了RequestQueue,調(diào)用了start()方法:
public void start() { this.stop(); this.mCacheDispatcher = new CacheDispatcher(this.mCacheQueue, this.mNetworkQueue, this.mCache, this.mDelivery); this.mCacheDispatcher.start(); for(int i = 0; i < this.mDispatchers.length; ++i) { NetworkDispatcher networkDispatcher = new NetworkDispatcher(this.mNetworkQueue, this.mNetwork, this.mCache, this.mDelivery); this.mDispatchers[i] = networkDispatcher; networkDispatcher.start(); } }
CacheDispatcher是緩存調(diào)度線程,并調(diào)用了start()方法,在循環(huán)中調(diào)用了NetworkDispatcher的start()方法,NetworkDispatcher是網(wǎng)絡(luò)調(diào)度線程,默認情況下mDispatchers.length為4,默認開啟了4個網(wǎng)絡(luò)調(diào)度線程,也就是說有5個線程在后臺運行并等待請求的到來。接下來我們創(chuàng)建各種的Request,并調(diào)用RequestQueue的add()方法:
publicRequest add(Request request) { request.setRequestQueue(this); Set var2 = this.mCurrentRequests; synchronized(this.mCurrentRequests) { this.mCurrentRequests.add(request); } request.setSequence(this.getSequenceNumber()); request.addMarker("add-to-queue"); //如果不能緩存,則將請求添加到網(wǎng)絡(luò)請求隊列中 if(!request.shouldCache()) { this.mNetworkQueue.add(request); return request; } else { Map var8 = this.mWaitingRequests; synchronized(this.mWaitingRequests) { String cacheKey = request.getCacheKey(); //之前是否有執(zhí)行相同的請求且還沒有返回結(jié)果的,如果有的話將此請求加入mWaitingRequests隊列,不再重復(fù)請求 if(this.mWaitingRequests.containsKey(cacheKey)) { Object stagedRequests = (Queue)this.mWaitingRequests.get(cacheKey); if(stagedRequests == null) { stagedRequests = new LinkedList(); } ((Queue)stagedRequests).add(request); this.mWaitingRequests.put(cacheKey, stagedRequests); if(VolleyLog.DEBUG) { VolleyLog.v("Request for cacheKey=%s is in flight, putting on hold.", new Object[]{cacheKey}); } } else { //沒有的話就將請求加入緩存隊列mCacheQueue,同時加入mWaitingRequests中用來做下次同樣請求來時的重復(fù)判斷依據(jù) this.mWaitingRequests.put(cacheKey, (Object)null); this.mCacheQueue.add(request); } return request; } } }
通過判斷request.shouldCache(),來判斷是否可以緩存,默認是可以緩存的,如果不能緩存,則將請求添加到網(wǎng)絡(luò)請求隊列中,如果能緩存就判斷之前是否有執(zhí)行相同的請求且還沒有返回結(jié)果的,如果有的話將此請求加入mWaitingRequests隊列,不再重復(fù)請求;沒有的話就將請求加入緩存隊列mCacheQueue,同時加入mWaitingRequests中用來做下次同樣請求來時的重復(fù)判斷依據(jù)。
從上面可以看出RequestQueue的add()方法并沒有做什么請求網(wǎng)絡(luò)或者對緩存進行操作。當(dāng)將請求添加到網(wǎng)絡(luò)請求隊列或者緩存隊列時,這時在后臺的網(wǎng)絡(luò)調(diào)度線程和緩存調(diào)度線程輪詢各自的請求隊列發(fā)現(xiàn)有請求任務(wù)則開始執(zhí)行,我們先看看緩存調(diào)度線程。
CacheDispatcher的run()方法:
public void run() { if(DEBUG) { VolleyLog.v("start new dispatcher", new Object[0]); } //線程優(yōu)先級設(shè)置為最高級別 Process.setThreadPriority(10); this.mCache.initialize(); while(true) { while(true) { while(true) { while(true) { try { //獲取緩存隊列中的一個請求 final Request e = (Request)this.mCacheQueue.take(); e.addMarker("cache-queue-take"); //如果請求取消了則將請求停止掉 if(e.isCanceled()) { e.finish("cache-discard-canceled"); } else { //查看是否有緩存的響應(yīng) Entry entry = this.mCache.get(e.getCacheKey()); //如果緩存響應(yīng)為空,則將請求加入網(wǎng)絡(luò)請求隊列 if(entry == null) { e.addMarker("cache-miss"); this.mNetworkQueue.put(e); //判斷緩存響應(yīng)是否過期 } else if(!entry.isExpired()) { e.addMarker("cache-hit"); //對數(shù)據(jù)進行解析并回調(diào)給主線程 Response response = e.parseNetworkResponse(new NetworkResponse(entry.data, entry.responseHeaders)); e.addMarker("cache-hit-parsed"); if(!entry.refreshNeeded()) { this.mDelivery.postResponse(e, response); } else { e.addMarker("cache-hit-refresh-needed"); e.setCacheEntry(entry); response.intermediate = true; this.mDelivery.postResponse(e, response, new Runnable() { public void run() { try { CacheDispatcher.this.mNetworkQueue.put(e); } catch (InterruptedException var2) { ; } } }); } } else { e.addMarker("cache-hit-expired"); e.setCacheEntry(entry); this.mNetworkQueue.put(e); } } } catch (InterruptedException var4) { if(this.mQuit) { return; } } } } } } } static { DEBUG = VolleyLog.DEBUG; }
看到四個while循環(huán)有些暈吧,讓我們挑重點的說,首先從緩存隊列取出請求,判斷是否請求是否被取消了,如果沒有則判斷該請求是否有緩存的響應(yīng),如果有并且沒有過期則對緩存響應(yīng)進行解析并回調(diào)給主線程。接下來看看網(wǎng)絡(luò)調(diào)度線程。
4.NetworkDispatcher網(wǎng)絡(luò)調(diào)度線程NetworkDispatcher的run()方法:
public void run() { Process.setThreadPriority(10); while(true) { long startTimeMs; Request request; while(true) { startTimeMs = SystemClock.elapsedRealtime(); try { //從隊列中取出請求 request = (Request)this.mQueue.take(); break; } catch (InterruptedException var6) { if(this.mQuit) { return; } } } try { request.addMarker("network-queue-take"); if(request.isCanceled()) { request.finish("network-discard-cancelled"); } else { this.addTrafficStatsTag(request); //請求網(wǎng)絡(luò) NetworkResponse e = this.mNetwork.performRequest(request); request.addMarker("network-http-complete"); if(e.notModified && request.hasHadResponseDelivered()) { request.finish("not-modified"); } else { Response volleyError1 = request.parseNetworkResponse(e); request.addMarker("network-parse-complete"); if(request.shouldCache() && volleyError1.cacheEntry != null) { //將響應(yīng)結(jié)果存入緩存 this.mCache.put(request.getCacheKey(), volleyError1.cacheEntry); request.addMarker("network-cache-written"); } request.markDelivered(); this.mDelivery.postResponse(request, volleyError1); } } } catch (VolleyError var7) { var7.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs); this.parseAndDeliverNetworkError(request, var7); } catch (Exception var8) { VolleyLog.e(var8, "Unhandled exception %s", new Object[]{var8.toString()}); VolleyError volleyError = new VolleyError(var8); volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs); this.mDelivery.postError(request, volleyError); } } }
網(wǎng)絡(luò)調(diào)度線程也是從隊列中取出請求并且判斷是否被取消了,如果沒取消就去請求網(wǎng)絡(luò)得到響應(yīng)并回調(diào)給主線程。請求網(wǎng)絡(luò)時調(diào)用this.mNetwork.performRequest(request),這個mNetwork是一個接口,實現(xiàn)它的類是BasicNetwork,我們來看看BasicNetwork的performRequest()方法:
public NetworkResponse performRequest(Request> request) throws VolleyError { long requestStart = SystemClock.elapsedRealtime(); while(true) { HttpResponse httpResponse = null; Object responseContents = null; Map responseHeaders = Collections.emptyMap(); try { HashMap e = new HashMap(); this.addCacheHeaders(e, request.getCacheEntry()); httpResponse = this.mHttpStack.performRequest(request, e); StatusLine statusCode1 = httpResponse.getStatusLine(); int networkResponse1 = statusCode1.getStatusCode(); responseHeaders = convertHeaders(httpResponse.getAllHeaders()); if(networkResponse1 == 304) { Entry requestLifetime2 = request.getCacheEntry(); if(requestLifetime2 == null) { return new NetworkResponse(304, (byte[])null, responseHeaders, true, SystemClock.elapsedRealtime() - requestStart); } requestLifetime2.responseHeaders.putAll(responseHeaders); return new NetworkResponse(304, requestLifetime2.data, requestLifetime2.responseHeaders, true, SystemClock.elapsedRealtime() - requestStart); } ...省略
從上面可以看到在12行調(diào)用的是HttpStack的performRequest()方法請求網(wǎng)絡(luò),接下來根據(jù)不同的響應(yīng)狀態(tài)碼來返回不同的NetworkResponse。另外HttpStack也是一個接口,實現(xiàn)它的兩個類我們在前面已經(jīng)提到了就是HurlStack和HttpClientStack。讓我們再回到NetworkDispatcher,請求網(wǎng)絡(luò)后,會將響應(yīng)結(jié)果存在緩存中,如果響應(yīng)結(jié)果成功則調(diào)用this.mDelivery.postResponse(request, volleyError1)來回調(diào)給主線程。來看看Delivery的postResponse()方法:
public void postResponse(Request> request, Response> response, Runnable runnable) { request.markDelivered(); request.addMarker("post-response"); this.mResponsePoster.execute(new ExecutorDelivery.ResponseDeliveryRunnable(request, response, runnable)); }
來看看ResponseDeliveryRunnable里面做了什么:
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) { this.mRequest = request; this.mResponse = response; this.mRunnable = runnable; } public void run() { if(this.mRequest.isCanceled()) { this.mRequest.finish("canceled-at-delivery"); } else { if(this.mResponse.isSuccess()) { this.mRequest.deliverResponse(this.mResponse.result); } else { this.mRequest.deliverError(this.mResponse.error); } if(this.mResponse.intermediate) { this.mRequest.addMarker("intermediate-response"); } else { this.mRequest.finish("done"); } if(this.mRunnable != null) { this.mRunnable.run(); } } } }
第17行調(diào)用了this.mRequest.deliverResponse(this.mResponse.result),這個就是實現(xiàn)Request
public class StringRequest extends Request{ private final Listener mListener; public StringRequest(int method, String url, Listener listener, ErrorListener errorListener) { super(method, url, errorListener); this.mListener = listener; } public StringRequest(String url, Listener listener, ErrorListener errorListener) { this(0, url, listener, errorListener); } protected void deliverResponse(String response) { this.mListener.onResponse(response); } ...省略 }
在deliverResponse方法中調(diào)用了this.mListener.onResponse(response),最終將response回調(diào)給了Response.Listener的onResponse()方法。我們用StringRequest請求網(wǎng)絡(luò)的寫法是這樣的:
RequestQueue mQueue = Volley.newRequestQueue(getApplicationContext()); StringRequest mStringRequest = new StringRequest(Request.Method.GET, "http://www.baidu.com", new Response.Listener() { @Override public void onResponse(String response) { Log.i("wangshu", response); } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { Log.e("wangshu", error.getMessage(), error); } }); //將請求添加在請求隊列中 mQueue.add(mStringRequest);
看到第5行整個Volley的大致流程都通了吧,好了關(guān)于Volley的源碼就講到這里。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/70590.html
摘要:前言想必很多人都用過,為了建立網(wǎng)絡(luò)編程的知識體系,是必須要講的知識點,所以我這里有必要再次介紹一下的使用。簡介在年大會上推出了一個新的網(wǎng)絡(luò)通信框架。在使用前請下載庫并放在目錄下并到工程中。 前言 Volley想必很多人都用過,為了建立網(wǎng)絡(luò)編程的知識體系,Volley是必須要講的知識點,所以我這里有必要再次介紹一下Volley的使用。 1.Volley簡介 在2013年Google I/...
閱讀 2643·2021-11-11 16:55
閱讀 680·2021-09-04 16:40
閱讀 3078·2019-08-30 15:54
閱讀 2615·2019-08-30 15:54
閱讀 2403·2019-08-30 15:46
閱讀 404·2019-08-30 15:43
閱讀 3227·2019-08-30 11:11
閱讀 2983·2019-08-28 18:17