想必大家都對Volley已經(jīng)很熟悉了吧,google工程師出的這個網(wǎng)絡(luò)框架代碼寫的是真好,值得我們大家去學(xué)習(xí),Volley之所以一出來就受到廣大程序員的歡迎,是因?yàn)樗梢杂梅浅:唵蔚姆椒▉戆l(fā)送Http請求,并且處理服務(wù)器返回的數(shù)據(jù),而且是直接返回到主線程,這樣是不是用起來很爽。
很早之前出的網(wǎng)絡(luò)框架,也很早就研究了,就是一直沒有寫,現(xiàn)在抽空寫出來分享給需要的人,寫的不好的地方請見諒。
Volley的簡單用法請看這個大神的博主Volley的簡單使用
Volley的框架圖

volley的整個流程其實(shí)很簡單:得到請求添加到緩存請求隊(duì)列中,然后經(jīng)過一系列的判斷,是否緩存中已經(jīng)有此請求,有取出,沒有放入網(wǎng)絡(luò)請求隊(duì)列中 ,最后都是將得到的結(jié)果返回到主線程中。
Volley整個框架是一個典型的生產(chǎn)消費(fèi)者模式 一個消費(fèi)者(CacheDispatcher) 也可以是下一個消費(fèi)者(NetworkDispatcher)的生產(chǎn)者。
接下來我們就從整個流程開始說
1.RequestQueue requestQueue = Volley.newRequestQueue(this);
顧名思義,這一步創(chuàng)建了一個requestQueue請求隊(duì)列。Volley.newRequestQueue(this),別看這個短短的一段代碼,其背后是做了整個volley的準(zhǔn)備工作。(后面我們會細(xì)講)
2.Request
StringRequest request = new StringRequest("https://www.baidu.com/", new Response.Listener<String>() {
@Override
public void onResponse(String response) {
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
}
});
public abstract class Request<T> implements Comparable<Request<T>>
這個Request是個泛型其中<T> 是你的返回類型。request實(shí)現(xiàn)Comparable這意味著是兩個request之間是可以比較。
Volley官方自帶了一些自己的request
- StringRequest
- ImageRequest
- JsonRequest
- JsonArrayRequest
- JsonObjectRequest
- ClearCacheRequest
我們也可以根據(jù)需求自己創(chuàng)建Request,在自定義Request的時候我們需要我們實(shí)現(xiàn)兩個抽象類:
void deliverResponse(T response)
Response<T> parseNetworkResponse(NetworkResponse response)
- 第一個方法是用來把解析的結(jié)果如何傳遞,一般都是用volley自帶的:Response.Listener<T> 回調(diào)接口傳遞。
2.第二個方法是用來把NetworkResponse解析成自己想的得到的結(jié)果,比如StringRequest,是轉(zhuǎn)換成Sting,ImageRequest是轉(zhuǎn)換成Bitmap。然后傳給第一個方法deliverResponse。
3. requestQueue.add(request);
接下來說一些這個RequestQueue
public RequestQueue(Cache cache, Network network, int threadPoolSize,
ResponseDelivery delivery) {
mCache = cache;
mNetwork = network;
mDispatchers = new NetworkDispatcher[threadPoolSize];
mDelivery = delivery;
}
創(chuàng)建RequestQueue需要的參數(shù)
- Cache:Volley使用的持久化磁盤緩存:DiskBasedCache(cacheDir)
- Network:進(jìn)行發(fā)送網(wǎng)絡(luò)請求的工具。
- int threadPoolsize:這個是NetworkDispatcher這個線程的數(shù)量。
- ResponseDelivery:用于傳遞請求結(jié)果的類。
RequestQueue的主要結(jié)構(gòu):
- Map<String, Queue<Request<?>>> mWaitingRequests :等待請求的集合,一些重復(fù)的請求存放區(qū)域,
- Set<Request<?>> mCurrentRequests:當(dāng)前請求的集合,包括了所有正在請求的,或者是等待請求的都放在這個集合中
- PriorityBlockingQueue<Request<?>> mCacheQueue:緩存隊(duì)列。(每一個請求在進(jìn)入隊(duì)列中都會先進(jìn)入這個緩存隊(duì)列)
- PriorityBlockingQueue<Request<?>> mNetworkQueue:網(wǎng)絡(luò)請求隊(duì)列。
- AtomicInteger mSequenceGenerator :這個類是給每個Request 生成序列號的。
然后我們來看一下add這個方法,都做了哪些事情
/**
* Adds a Request to the dispatch queue.
* @param request The request to service
* @return The passed-in 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.
A:
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.
if (!request.shouldCache()) {
mNetworkQueue.add(request);
return request;
}
B:
// Insert request into stage if there's already a request with the same cache key in flight.
synchronized (mWaitingRequests) {
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);
if (VolleyLog.DEBUG) {
VolleyLog.v("Request for cacheKey=%s is in flight, putting on hold.", cacheKey);
}
} else {
// Insert 'null' queue for this cacheKey, indicating there is now a request in
// flight.
mWaitingRequests.put(cacheKey, null);
mCacheQueue.add(request);
}
return request;
}
}
我在上面這段源碼中標(biāo)注了一下A,和B,我們可以看到使用了兩個同步鎖來往m
CurrentRequests,和mWaitingRequests 存放請求。
A中所有進(jìn)來的請求都添加進(jìn)去了。
B中我們看到mWaitingRequests 的Key是Request的key,Value是request。
我們來詳細(xì)講解一下創(chuàng)建RequestQueue
Volley.newRequestQueue();
這個方法首先會考慮你當(dāng)前的android的api是否>=9
如果大于等于9(3.0) Volley 會選擇使用HttpUrlConnectiion,小于9.0 選擇使用的是HttpClient。Volley分別創(chuàng)建了HurlStack,和HttpClientStack,來封裝這兩個網(wǎng)絡(luò)請求方法。Volley的RequestQueue只要持有Network接口就可以了。所有的網(wǎng)絡(luò)操作都在HttpStack的子類中進(jìn)行的。而NetWork接口中的performRequest方法調(diào)用了HttpSackt.performRequest方法就得到結(jié)果了。
queue.start();
/**
* Starts the dispatchers in this queue.
*/
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();
}
}
從代碼中可以看出,這個start方法是開啟了所有的Dispatcher(一個緩存線程,四個網(wǎng)絡(luò)請求線程),stop方法是停止線程的方法。
那么來看一下這兩個Dispatcher:
CacheDispatcher
創(chuàng)建CacheDispatcher所需要的參數(shù):
- BlockingQueue<Request<?>> cacheQueue :緩存隊(duì)列;
- BlockingQueue<Request<?>> networkQueue: 網(wǎng)絡(luò)請求隊(duì)列;
- Cache cache:磁盤緩存隊(duì)列;
- ResponseDelivery delivery:new ExecutorDelivery(new Handler(Looper.getMainLooper())); 這個類是調(diào)度請求結(jié)果到主線程的,可以看出在創(chuàng)建的時候,創(chuàng)建了一個handler,然后通過handler把結(jié)果發(fā)送到主線程,這就是為什么Volley得到的結(jié)果在主線程的原因(后面會詳細(xì)講解)。創(chuàng)建這個對象是在RequestQueue的構(gòu)造方法中創(chuàng)建的。
CacheDispatcher的run方法:
public void run() {
if (DEBUG) VolleyLog.v("start new dispatcher");
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
// Make a blocking call to initialize the cache.
mCache.initialize();
while (true) {
try {
// Get a request from the cache triage queue, blocking until
// at least one is available.
A:
final Request<?> request = mCacheQueue.take();
request.addMarker("cache-queue-take");
B:
// If the request has been canceled, don't bother dispatching it.
if (request.isCanceled()) {
request.finish("cache-discard-canceled");
continue;
}
C:
// Attempt to retrieve this item from cache.
Cache.Entry entry = mCache.get(request.getCacheKey());
if (entry == null) {
request.addMarker("cache-miss");
// Cache miss; send off to the network dispatcher.
mNetworkQueue.put(request);
continue;
}
D:
// If it is completely expired, just send it to the network.
if (entry.isExpired()) {
request.addMarker("cache-hit-expired");
request.setCacheEntry(entry);
mNetworkQueue.put(request);
continue;
}
// We have a cache hit; parse its data for delivery back to the request.
request.addMarker("cache-hit");
Response<?> response = request.parseNetworkResponse(
new NetworkResponse(entry.data, entry.responseHeaders));
request.addMarker("cache-hit-parsed");
E:
if (!entry.refreshNeeded()) {
// Completely unexpired cache hit. Just deliver the response.
mDelivery.postResponse(request, response);
} else {
// Soft-expired cache hit. We can deliver the cached response,
// but we need to also send the request to the network for
// refreshing.
request.addMarker("cache-hit-refresh-needed");
request.setCacheEntry(entry);
// Mark the response as intermediate.
response.intermediate = true;
F:
// Post the intermediate response back to the user and have
// the delivery then forward the request along to the network.
mDelivery.postResponse(request, response, new Runnable() {
@Override
public void run() {
try {
mNetworkQueue.put(request);
} catch (InterruptedException e) {
// Not much we can do about this.
}
}
});
}
} catch (InterruptedException e) {
// We may have been interrupted because it was time to quit.
if (mQuit) {
return;
}
continue;
}
}
}
我把整個代碼分成了幾段:
- A:可以看出來CacheDispatcher會一直While(true)的運(yùn)行,如果CacheQueue里面沒有Request的話,會被CacheQueue.take()阻塞;
- B:判斷Request是否已經(jīng)取消了。
- C: 獲得這個Reuqest在緩存中的結(jié)果。判斷是否為空,為空就把請求放到網(wǎng)絡(luò)請求隊(duì)列里面。
- D:判斷entry是否已經(jīng)失效了,失效放到網(wǎng)絡(luò)請求隊(duì)列。
-E:判斷entry需不需要從新請求,不需要的話就直接用過Delivery返回到主線程。需要的話,把它放到網(wǎng)絡(luò)請求線程。
NetworkDispatcher
這個和CacheDispatcher是差不多的就不詳細(xì)寫了,就是通過mNetwork.performRequest(request);進(jìn)行網(wǎng)絡(luò)請求得到結(jié)果,通過mDelivery.postResponse(request, response);發(fā)送到主線程。
ExecutorDelivery
ExecutorDeliver 實(shí)現(xiàn)了ResponseDelivery接口。主要工作就是把得到的結(jié)果傳遞到主線程。
我們來看一下他的構(gòu)造方法:
/**
* Creates a new response delivery interface.
* @param handler {@link Handler} to post responses on
*/
public ExecutorDelivery(final Handler handler) {
// Make an Executor that just wraps the handler.
mResponsePoster = new Executor() {
@Override
public void execute(Runnable command) {
handler.post(command);
}
};
}
構(gòu)造方法中創(chuàng)建了線程池來管理線程
Eexecutor 是一個異步執(zhí)行框架,將任務(wù)的提交和執(zhí)行解耦,基于生產(chǎn)者-消費(fèi)者模式,其提交任務(wù)的線程相當(dāng)于生產(chǎn)者,執(zhí)行任務(wù)的線程相當(dāng)于消費(fèi)者,用Runnable來表示任務(wù)。
在上面的CacheDispatcher和,NetWorkDispatcher中用到了這兩個方法
A : mDelivery.postResponse(request, response);
B: mDelivery.postResponse(request, response, new Runnable() );
這兩個方法:
A:這個方法其實(shí)調(diào)用的是B方法:
@Override
public void postResponse(Request<?> request, Response<?> response) {
postResponse(request, response, null);
}
B:
@Override
public void postResponse(Request<?> request, Response<?> response, Runnable runnable) {
request.markDelivered();
request.addMarker("post-response");
mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, runnable));
}
這個方法中調(diào)用了Delivery的execute方法,此方法的構(gòu)造方法傳入的是Runnable,,在runnable的run方法中調(diào)用了Reuqest的 mRequest.deliverResponse(mResponse.result);最后吧結(jié)果傳到了主線程。