解析Android框架之Volley源碼
我這里是以依賴架包的形式 ,大家也可以以gradle的形式進(jìn)行依賴。
好了,接下來(lái)上代碼了.....
//獲取volley的請(qǐng)求對(duì)象RequestQueue requestQueue = Volley.newRequestQueue(getApplicationContext());StringRequest stringRequest = new StringRequest(StringRequest.Method.GET, 'http://www.baidu.com', new Response.Listener<String>() { @Override public void onResponse(String s) {Log.d('MainActivity', '----->' + s); }}, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError volleyError) {Log.d('MainActivity', '---volleyError-->' + volleyError); }});requestQueue.add(stringRequest);
從代碼可以看出,首先newRequestQueue來(lái)獲取到一個(gè)請(qǐng)求隊(duì)列,然后在將StringRequest這個(gè)請(qǐng)求添加到請(qǐng)求隊(duì)列中,就可以了,就是這么簡(jiǎn)單。當(dāng)然請(qǐng)求不值StringRequest,還有JsonObjectRequest ,ImageRequest等等但是用法都是一樣的,這里就不貼代碼了。Volley的簡(jiǎn)單使用就這樣可以進(jìn)行請(qǐng)求了。是不是很簡(jiǎn)單
Volley執(zhí)行原理但是這個(gè)不是本篇的重點(diǎn),重點(diǎn)是分析一下這些是怎么執(zhí)行的。先上一張圖
我們先看看newRequestQueue這個(gè)內(nèi)部是怎么執(zhí)行的,代碼一開(kāi)始連續(xù)執(zhí)行了幾個(gè)重載方法,最后走到newRequestQueue
public static RequestQueue newRequestQueue(Context context, HttpStack stack, int maxDiskCacheBytes) { File cacheDir = new File(context.getCacheDir(), 'volley'); String userAgent = 'volley/0'; try {String packageName = context.getPackageName();PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0);userAgent = packageName + '/' + info.versionCode; } catch (NameNotFoundException var7) {; } //這里進(jìn)行了一個(gè)版本的判斷 2.3之前用的是HTTPClient,2.3之后使用的是HttpURLConnection if (stack == null) {if (VERSION.SDK_INT >= 9) { stack = new HurlStack();} else { stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));} } Network network = new BasicNetwork((HttpStack)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;}
在這里,我們看到了一個(gè)版本判斷,是不是瞬間感覺(jué)有點(diǎn)熟悉,沒(méi)錯(cuò),我們前面說(shuō)的,volley2.3之前用的是HTTPClient,2.3之后使用的是HttpURLConnection就是在這里進(jìn)行判斷的。接著看queue.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();} }
mCacheDispatcher是緩存調(diào)度線程,NetworkDispatcher是網(wǎng)絡(luò)調(diào)度線程,而這個(gè)this.mDispatchers.length系統(tǒng)默認(rèn)的大小為4,也就是說(shuō),在這里總共啟動(dòng)了5個(gè)線程在后臺(tái)運(yùn)行。
好了,到這里,就可以了,看源碼不要每一行都弄懂,不然,出不來(lái)了。到這里就拿到了這個(gè)RequestQueue對(duì)象。回過(guò)頭來(lái)看前面使用的代碼
//獲取volley的請(qǐng)求對(duì)象RequestQueue requestQueue = Volley.newRequestQueue(getApplicationContext());StringRequest stringRequest = new StringRequest(StringRequest.Method.GET, 'http://www.baidu.com', new Response.Listener<String>() { @Override public void onResponse(String s) {Log.d('MainActivity', '----->' + s); }}, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError volleyError) {Log.d('MainActivity', '---volleyError-->' + volleyError); }});requestQueue.add(stringRequest);
我們拿到這個(gè)RequestQueue對(duì)象以后,然后就把這個(gè)請(qǐng)求通過(guò)add方法添加到隊(duì)列中,我們看看這個(gè)add()方法是怎么執(zhí)行的。
public <T> Request<T> add(Request<T> request) {request.setRequestQueue(this);Set var2 = this.mCurrentRequests;synchronized(this.mCurrentRequests) { this.mCurrentRequests.add(request);}request.setSequence(this.getSequenceNumber());request.addMarker('add-to-queue');if (!request.shouldCache()) { //如果不能緩存 this.mNetworkQueue.add(request); return request;} else { Map var7 = this.mWaitingRequests; synchronized(this.mWaitingRequests) {String cacheKey = request.getCacheKey();if (this.mWaitingRequests.containsKey(cacheKey)) { //判斷之前是否執(zhí)行過(guò),但是還沒(méi)有返回結(jié)果 Queue<Request<?>> 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 {//沒(méi)有的話就將請(qǐng)求加入緩存隊(duì)列mCacheQueue,同時(shí)加入mWaitingRequests中用來(lái)做下次同樣請(qǐng)求來(lái)時(shí)的重復(fù)判斷依據(jù) this.mWaitingRequests.put(cacheKey, (Object)null); this.mCacheQueue.add(request);}return request; }} }
從代碼中可以看出,首先判斷是否可以緩存,當(dāng)然,默認(rèn)是可以緩存的。如果不能緩存的話,則通過(guò)this.mNetworkQueue.add(request);將請(qǐng)求添加到網(wǎng)絡(luò)請(qǐng)求隊(duì)列中。如果可以緩存,則還會(huì)判斷一次這個(gè)請(qǐng)求是否請(qǐng)求,如果執(zhí)行過(guò)就就通過(guò)this.mWaitingRequests.put(cacheKey, stagedRequests);添加到mWaitingRequests隊(duì)列,不在重復(fù)請(qǐng)求。否則就加入到緩存隊(duì)列。
大體的流程是這樣。現(xiàn)在我們看看緩存的,和網(wǎng)絡(luò)的是怎么執(zhí)行的。我們找到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,找到run()方法
public void run() {if (DEBUG) { VolleyLog.v('start new dispatcher', new Object[0]);}Process.setThreadPriority(10);this.mCache.initialize();while(true) { while(true) {while(true) { while(true) {try { while(true) {final Request<?> request = (Request)this.mCacheQueue.take(); //從緩存隊(duì)列中獲取到一個(gè)請(qǐng)求request.addMarker('cache-queue-take');if (request.isCanceled()) { //判斷請(qǐng)求是否取消,如果取消了,那就將該請(qǐng)求finish掉 request.finish('cache-discard-canceled');} else { Entry entry = this.mCache.get(request.getCacheKey()); if (entry == null) {//如果從緩存中取出來(lái)的內(nèi)容為空,則將請(qǐng)求加入到網(wǎng)絡(luò)線程中再次請(qǐng)求request.addMarker('cache-miss');this.mNetworkQueue.put(request); } else if (entry.isExpired()) { //如果請(qǐng)求過(guò)期了,則將請(qǐng)求加入到網(wǎng)絡(luò)線程中再次請(qǐng)求request.addMarker('cache-hit-expired');request.setCacheEntry(entry);this.mNetworkQueue.put(request); } else { //將數(shù)據(jù)回調(diào)到主線程request.addMarker('cache-hit');Response<?> response = request.parseNetworkResponse(new NetworkResponse(entry.data, entry.responseHeaders));request.addMarker('cache-hit-parsed');if (entry.refreshNeeded()) { request.addMarker('cache-hit-refresh-needed'); request.setCacheEntry(entry); response.intermediate = true; this.mDelivery.postResponse(request, response, new Runnable() {public void run() {try { CacheDispatcher.this.mNetworkQueue.put(request);} catch (InterruptedException var2) { ;}} });} else { this.mDelivery.postResponse(request, response);} }} }} catch (InterruptedException var4) { if (this.mQuit) {return; }} }} }} }
這里嵌套了幾個(gè)循環(huán),有點(diǎn)凌亂啊,但是慢慢分析的話,就會(huì)發(fā)現(xiàn),其實(shí)很清晰。我在注釋上面寫了,這里就不重復(fù)了
我們?cè)诳纯碞etworkDispatcher,看看網(wǎng)絡(luò)線程是怎么執(zhí)行的。一樣找到run()方法
public void run() {Process.setThreadPriority(10);while(true) { long startTimeMs; Request request; while(true) {startTimeMs = SystemClock.elapsedRealtime();try { request = (Request)this.mQueue.take(); //獲取到一個(gè)請(qǐng)求 break;} catch (InterruptedException var6) { if (this.mQuit) {return; }} } try {request.addMarker('network-queue-take');if (request.isCanceled()) { //如果請(qǐng)求取消了,則將請(qǐng)求finish掉 request.finish('network-discard-cancelled');} else {//進(jìn)行網(wǎng)絡(luò)請(qǐng)求 this.addTrafficStatsTag(request); NetworkResponse networkResponse = this.mNetwork.performRequest(request); request.addMarker('network-http-complete'); if (networkResponse.notModified && request.hasHadResponseDelivered()) {request.finish('not-modified'); } else {Response<?> response = request.parseNetworkResponse(networkResponse);request.addMarker('network-parse-complete');if (request.shouldCache() && response.cacheEntry != null) { this.mCache.put(request.getCacheKey(), response.cacheEntry); request.addMarker('network-cache-written');}request.markDelivered();this.mDelivery.postResponse(request, response); }} } 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); }} }
代碼比較多,我們直接找到NetworkResponse networkResponse = this.mNetwork.performRequest(request);這句代碼,這句代碼就是請(qǐng)求網(wǎng)絡(luò)的代碼,最核心的。performRequest是一個(gè)接口,我們看看這個(gè)performRequest()方法。Network在最開(kāi)始說(shuō)版本判斷的時(shí)候里面有一句代碼Network network = new BasicNetwork((HttpStack)stack); 從這句代碼,我們可以知道BasicNetwork才是最終實(shí)現(xiàn)網(wǎng)絡(luò)請(qǐng)求的類,我們找到performRequest方法
public NetworkResponse performRequest(Request<?> request) throws VolleyError {long requestStart = SystemClock.elapsedRealtime();while(true) { HttpResponse httpResponse = null; byte[] responseContents = null; Map responseHeaders = Collections.emptyMap(); try {Map<String, String> headers = new HashMap();this.addCacheHeaders(headers, request.getCacheEntry());httpResponse = this.mHttpStack.performRequest(request, headers);StatusLine statusLine = httpResponse.getStatusLine();int statusCode = statusLine.getStatusCode();responseHeaders = convertHeaders(httpResponse.getAllHeaders());if (statusCode == 304) { Entry entry = request.getCacheEntry(); if (entry == null) {return new NetworkResponse(304, (byte[])null, responseHeaders, true, SystemClock.elapsedRealtime() - requestStart); } entry.responseHeaders.putAll(responseHeaders); return new NetworkResponse(304, entry.data, entry.responseHeaders, true, SystemClock.elapsedRealtime() - requestStart);}if (statusCode == 301 || statusCode == 302) { String newUrl = (String)responseHeaders.get('Location'); request.setRedirectUrl(newUrl);}byte[] responseContents;if (httpResponse.getEntity() != null) { responseContents = this.entityToBytes(httpResponse.getEntity());} else { responseContents = new byte[0];}long requestLifetime = SystemClock.elapsedRealtime() - requestStart;this.logSlowRequests(requestLifetime, request, responseContents, statusLine);if (statusCode >= 200 && statusCode <= 299) { return new NetworkResponse(statusCode, responseContents, responseHeaders, false, SystemClock.elapsedRealtime() - requestStart);}throw new IOException(); } catch (SocketTimeoutException var12) {attemptRetryOnException('socket', request, new TimeoutError()); } catch (ConnectTimeoutException var13) {attemptRetryOnException('connection', request, new TimeoutError()); } catch (MalformedURLException var14) {throw new RuntimeException('Bad URL ' + request.getUrl(), var14); } catch (IOException var15) {int statusCode = false;NetworkResponse networkResponse = null;if (httpResponse == null) { throw new NoConnectionError(var15);}int statusCode = httpResponse.getStatusLine().getStatusCode();if (statusCode != 301 && statusCode != 302) { VolleyLog.e('Unexpected response code %d for %s', new Object[]{statusCode, request.getUrl()});} else { VolleyLog.e('Request at %s has been redirected to %s', new Object[]{request.getOriginUrl(), request.getUrl()});}if (responseContents == null) { throw new NetworkError(networkResponse);}networkResponse = new NetworkResponse(statusCode, (byte[])responseContents, responseHeaders, false, SystemClock.elapsedRealtime() - requestStart);if (statusCode != 401 && statusCode != 403) { if (statusCode != 301 && statusCode != 302) {throw new ServerError(networkResponse); } attemptRetryOnException('redirect', request, new AuthFailureError(networkResponse));} else { attemptRetryOnException('auth', request, new AuthFailureError(networkResponse));} }} }
代碼比較多,但是大多數(shù)代碼是判斷狀態(tài)返回碼的,不需要理會(huì)。
我們直接看httpResponse = this.mHttpStack.performRequest(request, headers);這一句代碼,HttpStack這個(gè)有沒(méi)有很熟悉。沒(méi)有??沒(méi)關(guān)系我在復(fù)制一次代碼
if (stack == null) { if (VERSION.SDK_INT >= 9) {stack = new HurlStack(); } else {stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent)); }}
還是在這個(gè)版本判斷這里,這里就是HurlStack就是真正的網(wǎng)絡(luò)請(qǐng)求的類了,網(wǎng)絡(luò)請(qǐng)求,就是寫在這個(gè)類里面的。好了,volley整個(gè)流程大概就是這樣了。現(xiàn)在大家回過(guò)頭看最初的哪一張圖,是不是明了很多。
以上就是解析Android框架之Volley源碼的詳細(xì)內(nèi)容,更多關(guān)于Android框架之Volley源碼的資料請(qǐng)關(guān)注好吧啦網(wǎng)其它相關(guān)文章!
相關(guān)文章:
1. IntelliJ IDEA設(shè)置默認(rèn)瀏覽器的方法2. idea設(shè)置提示不區(qū)分大小寫的方法3. HTTP協(xié)議常用的請(qǐng)求頭和響應(yīng)頭響應(yīng)詳解說(shuō)明(學(xué)習(xí))4. IntelliJ IDEA創(chuàng)建web項(xiàng)目的方法5. VMware中如何安裝Ubuntu6. ASP.NET MVC通過(guò)勾選checkbox更改select的內(nèi)容7. .NET SkiaSharp 生成二維碼驗(yàn)證碼及指定區(qū)域截取方法實(shí)現(xiàn)8. CentOS郵件服務(wù)器搭建系列—— POP / IMAP 服務(wù)器的構(gòu)建( Dovecot )9. docker容器調(diào)用yum報(bào)錯(cuò)的解決辦法10. django創(chuàng)建css文件夾的具體方法
