1.概述
Volley的源代碼分析,網上一大把的分析博客,但是當你看完這些博客后,也是云里霧里的,很多一上來就上源代碼分析,典型的就是這一篇:
http://blog.csdn.net/guolin_blog/article/details/17656437
還有從結構上講,總的來說,比上從源代碼講強那么一點,典型的就是這一篇。單總的來說,這一篇比上一篇強一點。
對于一上來就開始分析源代碼的行為,我敬而遠之。
現在回過頭來看Volley的源代碼,感覺從設計的角度來說,Volley設計并不算是優秀,但是volley的擴展性非常棒,面向接口編程在這里得到完美的體現,這是閱讀volley源代碼之后的最大感受。
volley的類沒有幾個,對于打基礎的階段,閱讀該庫對提升技術水平有很好的幫助。
volley說明

從名字由來和配圖中無數急促的火箭可以看出 Volley 的特點:特別適合數據量小,通信頻繁的網絡操作。
對于文件上傳,文件下載等操作,還是換成另外的庫吧。至于為什么,因為其設計就決定了。
源碼分析方法

其實Volley的設計思路和源碼分析的方式在上面的這個圖就已經高度的概括展示出來了。這張圖已經說明了volley的工作原理和設計思路。
這是是volley源代碼的結構:
源代碼分析
我們先不看 "toolbox"文件夾,因為該文件夾主要是其接口的實現。
現在我們看下面一些無關緊要的類:
- VolleyLog。
是一個日志類,與此無關,去掉。
- VolleyError,TimeOutError,ServerError,ParseError,NetworkError,AuthFailureError,NoConnectionError。
這些都是異常的錯誤處理,其中后面的Error相關的類都時VolleyError的子類,這個對分析volley結構沒有什么幫助,去掉不看。
- RetryPolicy ,DefaultRetryPolicy。
后者是前者的子類,我們只看RetryPolicy這個就行了。實際上這個是是重置訪問,比如本次訪問超時,設置20s后再次連接,這個就是重置的作用,對于分析Volley的整個結構來說,無關緊要,可以不看。在分析具體的代碼和細節的時候再去看。
- ResponseDelivery 和 ExecutorDelivery。
后者是前者的一個實現。這個類作用就是異步操作,實際上就是一個Hanlder的事件分發,將子線的結果分發到主線程中。分析結構的時候,只需要關心ResponseDelivery。
- Cache 緩存的接口。
去掉上面那那些無關緊要的類之后,剩下就沒有幾個類了,我們看看還剩下那些類。
Network 具體的網絡訪問
CacheDispatcher 緩存調度線程
NetworkDispatcher 網絡訪問調度線程
NetworkResponse 網絡訪問的直接結果,不是分發到主線程的結果
Request 網絡請求的封裝,包括請求的url,請求的方法,請求的的內容等等。
RequestQueue 這個看起來好像是一個請求的對象,實際上這個只是將這些類根據規則組合在一起的東西。源代碼的分析就是從這里從這個類開始進行的。
Response 封裝了分發的結果,這個怎么理解呢,就是 NetworkRespond的結果經過進一步處理分發到主線程中的結果。
怎么樣,剩下的也沒有幾個,這樣就大大的降低了閱讀代碼的難度了。
RequestQueue開始
這個類是整個Volley的開始部分,先看start()方法:
public void start() {
stop(); // Make sure any currently running dispatchers are stopped.
// Create the cache dispatcher and start it.
mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery);
mCacheDispatcher.start();
// Create network dispatchers (and corresponding threads) up to the pool size.
for (int i = 0; i < mDispatchers.length; i++) {
NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork,
mCache, mDelivery);
mDispatchers[i] = networkDispatcher;
networkDispatcher.start();
}
}
前面說過了,CacheDispatcher和NetworkDispatcher是兩個線程一個是緩存調度線程,一個是網絡請求調度的線程。
上面的代碼就是開啟一個緩存調度線程和若干個(默認四個)網絡請求調度線程。
接下來我們看看CacheDispatcher線程。
CacheDispatcher線程
既然是一個線程,那么我們只關心 線程run方法就可以了
下面是偽代碼,剔除一些日志,異常判斷等無影響代碼后的結構
while(true){
//先從緩存隊列中拿出一個請求
final Request request = mCacheQueue.take();
//如果這個請求取消了,那么這個請求直接結束,開始下一個循環
if (request.isCanceled()) {
request.finish("cache-discard-canceled");
ontinue;
}
// 如果沒有緩存或者緩存失效的話,就將這條請求添加到網絡請求調度線程中
Cache.Entry entry = mCache.get(request.getCacheKey());
if (entry == null || entry.isExpired()) {
mNetworkQueue.put(request);
continue;
}
//從緩存中拿出結果。
Response response = request.parseNetworkResponse(
new NetworkResponse(entry.data, entry.responseHeaders));
request.addMarker("cache-hit-parsed");
//分發結果
mDelivery.postResponse(request, response);
}
從上面的偽代碼可以看出,實際上緩存調度線程做的事情非常的簡單,邏輯一點也不復雜。
先從緩存隊列中拿出一條請求。
判斷這個請求是否已經標志結束了,如果結束了那么設置這條請求結束,并分發結果。否則進入下一步。
判斷緩存是否存在,緩存是否過期,如果過期了,之前沒有緩存,那么就將這條請求放到網絡調度的線程中。
NetworkDispatcher
網絡請求調度線程的分析方法和上面類似,實際上,該類的run()方法中的代碼比CacheDispatcher 線程中 run()方法中代碼還少,無非就是:
從網絡請求隊列中拿出一條request。
判斷這條請求是否已經結束或者取消了。如果沒有那么就是下一步。
開始執行網絡請求,并拿到請求的結果。
是否需要緩存結果,如果需要緩存結果,那么就緩存結果。
將請求的結果進行分發。
完成上面的步驟之后,實際上volley的核心代碼就分析完成了,其它部分就是細節的問題,比如具體的網絡請求是怎么樣子的。分發是什么樣子的,但這些都是細節問題,不是主干代碼。
對于初學者來說,很容易陷入代碼汪洋中,即使把代碼全部看一篇也無濟于事,抓住枝葉,不見主干,分析再多也沒有用。典型的例子有:
http://blog.csdn.net/guolin_blog/article/details/17656437
總結:
閱讀源代碼的方式我總結如下:
首先看一看設計的結構圖。
去掉無關緊要的類,比如異常Error相關的類,日志類等。
分析主干代碼,比如重點看接口和抽象類而忽略掉其具體的實現,因為優秀的開源庫一定是面向接口編程,這些接口和抽象類才是設計的框架所在。
在分析過程中去掉無用的代碼,這里的無用指的是那些為了框架穩定性和環境適配的代碼,如NUll指針判斷,日志記錄,異常等。
使用偽代碼自己實現一遍框架。