Vollery原始碼閱讀(二)
上節寫到關於
Vollery
的前半部分,需要檢視的點選 , 這次主要檢視當我們真正add request
的時候做進一步檢視。
我們還是從使用的方法作為我們的切入點:
mQueue.add(postRequest);//當我們向佇列中新增一個網路請求
跟進,檢視 RequestQueue#add()
方法:
/** * Staging area for requests that already have a duplicate request in * flight. * 儲存有重複請求的request暫存區,我個人認為就是如果 正在處理A發出的一個請求,此時又來一個A發出同樣的一個請求,那麼第二個請求就會暫時儲存在這個集合中 */private final Map<String, Queue<Request<?>>> mWaitingRequests = new HashMap<String, Queue<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. request.setRequestQueue(this); synchronized (mCurrentRequests) { mCurrentRequests.add(request); } // 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. //判斷是否可以快取了,不快取就新增到網路請求佇列中去return,前面已經說過這個 mNetworkQueue 儲存管理網路請求佇列的 //預設是可以快取的,在Request的構造方法可以看到 //public Request(int method, String url, ErrorListener listener) { // this.mShouldCache = true; // } 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) { //首先檢視是否快取過,取key 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); } else { //第一次請求,應該是進入到這裡的 // Insert 'null' queue for this cacheKey, indicating there is // now a request in // flight. //新增一個 null 佇列,表示有一個請求正在進行 mWaitingRequests.put(cacheKey, null); //新增到快取佇列中,那麼我們接下來重點檢視CacheDispatcher#run方法 mCacheQueue.add(request); } return request; } }
接下來就到 CacheDispatcher#run()
方法了,因為裡面有值了。
public void run() { Process.setThreadPriority(10); //初始化快取型別有兩種目前:NoCache() 和 DiskBaseCache() this.mCache.initialize(); //巢狀了好多 while 迴圈 while(true) { while(true) { while(true) { while(true) { try { //從快取佇列中取出,在之前第一篇文章時,沒展示下半部分,這次有請求就可以看下里面的邏輯了。 final Request<?> request = (Request)this.mCacheQueue.take(); request.addMarker("cache-queue-take"); //請求未取消 if (request.isCanceled()) { request.finish("cache-discard-canceled"); } else { //拿到快取結果,請求資訊都儲存一個叫Entry內部類中 Entry entry = this.mCache.get(request.getCacheKey()); //有可能取出的快取為null if (entry == null) { request.addMarker("cache-miss"); //如果清空了快取,那就重新新增到網路請求佇列中去 this.mNetworkQueue.put(request); } else if (!entry.isExpired()) {//判斷是否過期 request.addMarker("cache-hit"); //拿到請求結果response Response<?> response = request.parseNetworkResponse(new NetworkResponse(entry.data, entry.responseHeaders)); request.addMarker("cache-hit-parsed"); //表示是否需要重新重新整理 if (!entry.refreshNeeded()) { //不需要的話就直接分發給主執行緒了 this.mDelivery.postResponse(request, response); } else { //需要重新整理,就重新進行網路請求 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 { //表示過期了,也重新進行請求 request.addMarker("cache-hit-expired"); request.setCacheEntry(entry); this.mNetworkQueue.put(request); } } } catch (InterruptedException var4) { if (this.mQuit) { return; } }
關於 CacheDispatcher#run
類我畫了一張圖示:
CacheDispatcher.png
從這裡我們知道,網路請求首先需要mCacheDispatcher
判斷是否已快取,若快取了則直接 postResponse
如果沒有,則重新進行網路請求,我們就直接新增到 mNetworkQueue
中,那第一次請求,肯定還未快取, 那我們下面就又可以看這個 NetworkDispatcher#run
方法了,因為此時佇列中有請求了,接下來我們再返回檢視:
NetworkDispatcher#run()
方法:
public void run() { //設定執行緒優先順序 Process.setThreadPriority(10); while(true) { Request request; while(true) { try { //從這個網路請求佇列中中取出一條request //第二次這裡有了,因為我們add 了 一個 request request = (Request)this.mQueue.take(); break; } catch (InterruptedException var4) { if (this.mQuit) { return; } } } //以下都是網路請求佇列有網路請求任務時執行 request.addMarker("network-queue-take"); if (request.isCanceled()) {//判斷是否取消 request.finish("network-discard-cancelled"); } else { //網路請求未取消 this.addTrafficStatsTag(request); //處理網路請求,得到NetworkResponse NetworkResponse networkResponse = this.mNetwork.performRequest(request); //標識請求完成 request.addMarker("network-http-complete"); if (networkResponse.notModified && request.hasHadResponseDelivered()) { request.finish("not-modified"); } else { //開始解析返回的結果,解析parseNetworkResponse可根據不同型別的方式進行解析,請看下圖: 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"); } //分發請求結果透過 mDelivery 完成 request.markDelivered(); this.mDelivery.postResponse(request, response); } } }
解析 有Json
Image
String
等多種型別。
image.png
到此基本分析完畢。奉上一個整體流程圖,我在網上找到的,感覺還不錯:
作者:糖葫蘆_倩倩
連結:
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/200/viewspace-2821994/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Vollery原始碼閱讀(—)原始碼
- 【原始碼閱讀】Glide原始碼閱讀之load方法(二)原始碼IDE
- 【原始碼閱讀】AndPermission原始碼閱讀原始碼
- 原始碼閱讀:SDWebImage(二)——SDWebImageCompat原始碼Web
- RIPS原始碼閱讀記錄(二)原始碼
- 原始碼閱讀:AFNetworking(二)——AFURLRequestSerialization原始碼
- 【詳解】ThreadPoolExecutor原始碼閱讀(二)thread原始碼
- 【原始碼閱讀】Glide原始碼閱讀之with方法(一)原始碼IDE
- 【原始碼閱讀】Glide原始碼閱讀之into方法(三)原始碼IDE
- Spring原始碼閱讀——ClassPathXmlApplicationContext(二)Spring原始碼XMLAPPContext
- 逐行閱讀redux原始碼(二)combineReducersRedux原始碼
- Koa原始碼閱讀(二)上下文ctx原始碼
- basictracer-go原始碼閱讀二——SpanGo原始碼
- ReactorKit原始碼閱讀React原始碼
- AQS原始碼閱讀AQS原始碼
- CountDownLatch原始碼閱讀CountDownLatch原始碼
- HashMap 原始碼閱讀HashMap原始碼
- delta原始碼閱讀原始碼
- 原始碼閱讀-HashMap原始碼HashMap
- NGINX原始碼閱讀Nginx原始碼
- Mux 原始碼閱讀UX原始碼
- HashMap原始碼閱讀HashMap原始碼
- fuzz原始碼閱讀原始碼
- RunLoop 原始碼閱讀OOP原始碼
- express 原始碼閱讀Express原始碼
- muduo原始碼閱讀原始碼
- stack原始碼閱讀原始碼
- TiCDC 原始碼閱讀(二)TiKV CDC 模組介紹原始碼
- PostgreSQL 原始碼解讀(3)- 如何閱讀原始碼SQL原始碼
- JDK原始碼閱讀:Object類閱讀筆記JDK原始碼Object筆記
- Laravel 原始碼閱讀 - QueueLaravel原始碼
- 使用OpenGrok閱讀原始碼原始碼
- 如何閱讀Java原始碼?Java原始碼
- buffer 原始碼包閱讀原始碼
- 原始碼閱讀技巧篇原始碼
- 如何閱讀框架原始碼框架原始碼
- 再談原始碼閱讀原始碼
- Laravel 原始碼閱讀 - EloquentLaravel原始碼