Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> android - Volley源碼分析

android - Volley源碼分析

編輯:關於Android編程

我有一篇文章很不負責的,沒有頭緒的分析了一些Volley的源碼。我自己回頭去看了一下,於是就把他刪掉了,於是就有了今天的這篇文章。

Volley的使用步驟

創建一個RequestQueue對象。 創建一個Request對象。 將Request對象添加到RequestQueue裡面。

我們可以看到使用非常的簡單,順著這個邏輯我們在來看一遍源碼

1.創建RequestQueue對象

RequestQueue mQueue = Volley.newRequestQueue(context);

在newRequestQueue方法中創建了一個Cache一個newWork,然後用這兩個創建了一個RequestQueue,隨後啟動這個請求隊列,這個隊列啟動的是5個線程(默認是1個處理走緩存的請求的線程,4個處理網絡請求的線程,其實這裡可以自己改,走緩存的請求個人覺得1個就足夠,處理網絡請求的線程數可以根據cpu核數等因素自己來確定一個合理值),在5個線程中主要的工作就是在自己的while循環中不斷的讀取隊列中的內容(1個走緩存的請求隊列,之後都稱為A,1個走網絡的請求隊列,之後都稱為B),也就是1個線程不斷從A中讀數據,4個線程不斷從B中讀數據。A、B中沒有數據的時候,也就是take拿到的數據為空時,take就會阻塞所在的線程,take不為空的話,就進行各自的處理,一個走緩存,一個走網絡。
走緩存:
這裡寫圖片描述
走網絡:
這裡寫圖片描述

其中一些細節可能大家不太明白,比如:走網絡中的304響應、為什麼使用隊列不用線程池(其實是可以用線程池),像上面這些比較細枝末節的在之後會講解。<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxoMiBpZD0="2創建一個request對象">2.創建一個Request對象

這一部分是我當時讀源碼的時候比較難受的一部分,裡面有很多我當時不知道什麼用的參數,有http請求報文相關的參數,而且和network緊密相連,而這個network對於我這種一開始http協議不怎麼了解的人來說簡直就是痛苦,什麼請求首部、請求主體,完全就是想要頭大,難怪很多人都是建議不要自己來寫網絡請求框架,是有道理的不容易寫,更不容易寫好,我也就不談自己對於其中http請求實現的粗淺的理解,不誤人子弟了,有興趣大家可以和我一樣去啃http權威指南。對於我們想要去實現自己的請求,主要關注的就4個方法:

abstract protected Response parseNetworkResponse(NetworkResponse response);

子類重寫此方法,將網絡返回的原生字節內容,轉換成合適的類型。此方法會在工作線程中被調用。

abstract protected void deliverResponse(T response);

子類重寫此方法,將解析成合適類型的內容傳遞給它們的監聽回調。

public byte[] getBody()
protected Map getParams()

上述兩個方法就是寫請求主體的內容。像一般我們知道的post是需要有請求主體的

3.將Request對象add到RequestQueue裡面

這個將請求add到RequestQueue其實就沒什麼好講的,就是將請求添加到隊列中。但這裡還是展開具體的講一講比較能幫助理解,首先,執行添加的add函數之後,就將這個請求和這個請求隊列相關聯(方便之後結束請求),隨後將此請求添加到mCurrentRequests 這個集合中,我們看一下他的聲明

private final Set> mCurrentRequests = new HashSet>();

它的作用是維護了一個正在進行中,尚未完成的請求集合。因為是set所以其中的請求是不會重復的。
隨後給這個請求設置一個請求的標號,判斷請求是否要緩存,要就加入到緩存請求隊列,否則加入網絡請求隊列,對於之後重復的請求(前提:要緩存的)都加入到mWaitingRequests 集合中

private final Map>> mWaitingRequests = new HashMap>>();

我們再繼續講,將請求添加到請求隊列中之後,這個請求就會有很多種後續的可能:請求自然結束(就是請求成功了或者請求失敗,我們沒有手動的去結束這個請求)、主動結束(比如我們打開一個activity,在其中創建了一個請求添加到隊列中,但是我們很快就離開了這個頁面,並且我們不想要這個請求還在隊列中占用資源,因為它並不重要,於是我們就主動的結束這個請求),結束請求最終調用的是void finish(Requestrequest) 方法,首先從正在進行中請求集合mCurrentRequests中移除該請求。 然後查找請求等待集合mWaitingRequests中是否存在等待的請求,如果存在,則將等待隊列移除,並將等待隊列所有的請求添加到緩存請求隊列中,讓緩存請求處理線程CacheDispatcher自動處理。
一開始我讀到這裡的時候會覺得(如果存在,則將等待隊列移除,並將等待隊列所有的請求添加到緩存請求隊列中,讓緩存請求處理線程CacheDispatcher自動處理。)這一步有問題,但仔細理解了之後其實是自己想的太少了,只要最後都執行了請求的finish也就是請求隊列的finish方法就不會有問題,所有的請求都會執行。

響應與分發

上面的內容我講完了創建請求將請求添加到請求隊列,並不斷從隊列中讀取請求進行處理,到這裡我們自然會問的就是之後呢?對啊!之後呢,請求之後得到響應,並將響應分發給請求者。

響應

如何響應,首先一開始什麼都沒有肯定從網絡中拿,那麼我們就從網絡的隊列開始,去除一個請求之後執行Basicwork(或者自己實現,只要繼承Network接口就行)的performRequest方法,在其中有調用我們在創建請求隊列的時候傳入的httpstack對象執行其中的performRequest方法,首先做的事情是設置一些請求報文首部的參數,之後就是真正的執行http請求獲取響應報文的數據返回,在Basicwork的performRequest方法中解析響應報文的信息獲取起始行中的狀態碼,根據不同的狀態碼執行不同的操作,主要的就是200和304

下面一幅圖幫助理解
這裡寫圖片描述

分發

主要就是

一些細節的講解

在下面講解一些比較細的,但是很可能會在閱讀源碼的時候有問題的點。

為什麼在RequestQueue中緩存請求隊列和網絡請求隊列添加數據方法使用的是add而不是put

兩個隊列聲明如下:

private final PriorityBlockingQueue> mCacheQueue = new PriorityBlockingQueue>();

private final PriorityBlockingQueue> mNetworkQueue = new PriorityBlockingQueue>();

對於BlockingQueue它的put和add方法是有區別的,add方法在在隊列滿的時候是直接拋出異常,而put方法是會阻塞,相比之下,RequestQueue基本都是會在ui線程中使用的,如果阻塞就會有anr錯誤,直接就是程序奔潰,那還是異常比較好一些。(再深入有異常怎麼辦,好像也沒看到異常捕獲,我自己也去查了一下,沒有查到就沒有繼續深究,畢竟這種情況基本不會出現,有興趣可以自己去查查看)

為什麼使用工作線程任務隊列而不用線程池

不斷的創建新的線程銷毀線程是很好資源的,所以對於頻繁的網絡請求就需要復用已有工作線程,這樣做同時也可以避免出現同一時間出現大量的線程的情況。就這兩點來看,其實是也可以使用線程池的,都能達到要求。但是我們可以先看看Volley的設計目標就是非常適合去進行數據量不大,但通信頻繁的網絡操作,而對於大數據量的網絡操作,比如說下載文件等,Volley的表現就會非常糟糕。從這個目標出發工作線程任務隊列適合處理大量耗時較短的任務,並且我個人覺得如果使用線程池的話編寫的難度上比使用線程任務隊列大,而且就最終的性能上我不覺得會有什麼差別,可能就一點:靈活性上來說線程池更加優越,總的來說就是兩個能用同樣的性能達到同樣的效果,當然是選擇更容易使用的。

處理走網絡的請求中的304響應

304是http響應報文返回時都會攜帶的一個狀態碼,304的意思是和服務器的數據比對之後發現沒有改變,我們常常會遇到的還有200:表示正確返回,404:沒有找到,302:重定向。著一部分其實是http協議的內容,有興趣的可以去讀一下http權威指南這本書,我也正在讀,如果自己想要搞一個網站什麼的,我覺得是必定要學好http協議的,對於編寫http相關程序也是幫助很大。

為什麼讀取請求隊列中請求的5個線程啟動之後都指定了優先級

我們可以發現在CacheDispatcher和NetworkDispatcher中都有這麼一句話

Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);

什麼意思呢,也就是指定了線程的優先級,不要覺得線程干嘛還要指定優先級啊,不注意使用的話你的ui線程會出現卡頓的情況!

上面的細節問題都是我自己當時看的時候,會有障礙的地方,所以就列出來給大家提個醒,沒有問題的也看看幫我看看我的理解是否有誤,如果有朋友還有什麼不懂的問題,可以在文章下留言,我會將覺得有必要解釋的問題添加到文章中。
今天先到這裡,還有一些沒有分析的,後續更新。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved