Volley的工作原理
- 線程管理
- 緩存的管理
- 發(fā)送網(wǎng)絡(luò)請(qǐng)求過程
- 在主線程把請(qǐng)求加入請(qǐng)求隊(duì)列
- 緩存線程查詢請(qǐng)求是否有緩存榴徐,如果有緩存,則從緩存中獲取數(shù)據(jù)解析返回給主線程攻柠,如果沒有緩存怀吻,把請(qǐng)求分發(fā)給網(wǎng)絡(luò)線程
- 網(wǎng)絡(luò)線程發(fā)送請(qǐng)求,從服務(wù)器獲取數(shù)據(jù)惠遏,解析后返回給主線程
Volley源碼分析
? 首先,從創(chuàng)建請(qǐng)求隊(duì)列開始看
Volley.newRequestQueue(context);
? 點(diǎn)擊進(jìn)去跳到Volley類,然后就會(huì)跳到這個(gè)方法里面.
public static RequestQueue newRequestQueue(Context context, HttpStack stack) {
File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR); //這里創(chuàng)建了一個(gè)緩存目錄,具體路徑在data/data/包名/cache/DEFAULT_CACHE_DIR所指向的文件名里面
String userAgent = "volley/0";
try {
String packageName = context.getPackageName();
PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0);
userAgent = packageName + "/" + info.versionCode;
} catch (NameNotFoundException e) {
}
if (stack == null) {
if (Build.VERSION.SDK_INT >= 9) { //如果當(dāng)前的構(gòu)建版本大于SDK9 就用HurlStack為HttpStack賦值,HttpStack內(nèi)部用HttpUrlConnection來創(chuàng)建網(wǎng)絡(luò)連接
stack = new HurlStack();
} else { //否則就用HttpClientStack來為HttpStack賦值,HttpClientStack里面使用HttpClient來創(chuàng)建網(wǎng)絡(luò)連接
// Prior to Gingerbread, HttpUrlConnection was unreliable.
// See: http://android-developers.blogspot.com/2011/09/androids-http-clients.html
stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));
}
}
Network network = new BasicNetwork(stack);
RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir), network);
queue.start();
return queue;
}
? 我們進(jìn)去看一下HttpStack類
public interface HttpStack {
/**
* Performs an HTTP request with the given parameters.
*
* <p>A GET request is sent if request.getPostBody() == null. A POST request is sent otherwise,
* and the Content-Type header is set to request.getPostBodyContentType().</p>
*
* @param request the request to perform
* @param additionalHeaders additional headers to be sent together with
* {@link Request#getHeaders()}
* @return the HTTP response
*/
public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)
throws IOException, AuthFailureError;
}
? 發(fā)現(xiàn)這是一個(gè)接口,那就看一下他的實(shí)現(xiàn)類HurlStack,查看該類的實(shí)現(xiàn)方法
public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)
throws IOException, AuthFailureError {
String url = request.getUrl();
HashMap<String, String> map = new HashMap<String, String>();
map.putAll(request.getHeaders());
map.putAll(additionalHeaders);
if (mUrlRewriter != null) {
String rewritten = mUrlRewriter.rewriteUrl(url);
if (rewritten == null) {
throw new IOException("URL blocked by rewriter: " + url);
}
url = rewritten;
}
URL parsedUrl = new URL(url);
HttpURLConnection connection = openConnection(parsedUrl, request); //使用HttpURLConnection來打開網(wǎng)絡(luò)連接
for (String headerName : map.keySet()) {
connection.addRequestProperty(headerName, map.get(headerName));
}
setConnectionParametersForRequest(connection, request);
// Initialize HttpResponse with data from the HttpURLConnection.
ProtocolVersion protocolVersion = new ProtocolVersion("HTTP", 1, 1);
int responseCode = connection.getResponseCode();
if (responseCode == -1) {
// -1 is returned by getResponseCode() if the response code could not be retrieved.
// Signal to the caller that something was wrong with the connection.
throw new IOException("Could not retrieve response code from HttpUrlConnection.");
}
StatusLine responseStatus = new BasicStatusLine(protocolVersion,
connection.getResponseCode(), connection.getResponseMessage());
BasicHttpResponse response = new BasicHttpResponse(responseStatus);
if (hasResponseBody(request.getMethod(), responseStatus.getStatusCode())) {
response.setEntity(entityFromConnection(connection));
}
for (Entry<String, List<String>> header : connection.getHeaderFields().entrySet()) {
if (header.getKey() != null) {
Header h = new BasicHeader(header.getKey(), header.getValue().get(0));
response.addHeader(h);
}
}
return response;
}
? 我們發(fā)現(xiàn)這個(gè)方法主要是在構(gòu)建網(wǎng)絡(luò)連接,里面是使用HttpURLConnection來網(wǎng)絡(luò)連接,然后返回HttpResponse響應(yīng).
繼續(xù)回到newRequestQueue方法里面
Network network = new BasicNetwork(stack);
RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir), network);
queue.start();
? 代碼執(zhí)行到這里了,我們看一下這行代碼,這里傳入了兩個(gè)參數(shù),一個(gè)是基于磁盤的緩存,一個(gè)是網(wǎng)絡(luò)連接.進(jìn)去DiskBasedCache類看一下
RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir), network);
public DiskBasedCache(File rootDirectory) {
this(rootDirectory, DEFAULT_DISK_USAGE_BYTES);
}
? 可以看出這里設(shè)置了緩存的目錄以及默認(rèn)使用緩存的大小
private static final int DEFAULT_DISK_USAGE_BYTES = 5 * 1024 * 1024;
? 默認(rèn)緩存的大小為5M.
我們最后進(jìn)入RequestQueue里面看一下構(gòu)造方法做了一些什么事情
public RequestQueue(Cache cache, Network network) {
this(cache, network, DEFAULT_NETWORK_THREAD_POOL_SIZE);
}
繼續(xù)點(diǎn)擊進(jìn)去,
public RequestQueue(Cache cache, Network network, int threadPoolSize) {
this(cache, network, threadPoolSize,
new ExecutorDelivery(new Handler(Looper.getMainLooper())));
}
再次點(diǎn)擊進(jìn)去,最終是調(diào)用這個(gè)構(gòu)造方法
public RequestQueue(Cache cache, Network network, int threadPoolSize,
ResponseDelivery delivery) {
mCache = cache; //根據(jù)上面封裝的構(gòu)造方法,這里傳進(jìn)來的是new DiskBasedCache(cacheDir)
mNetwork = network;//這里傳進(jìn)來的是new BasicNetwork(stack)
mDispatchers = new NetworkDispatcher[threadPoolSize];//threadPoolSize傳進(jìn)來的是 DEFAULT_NETWORK_THREAD_POOL_SIZE,根據(jù)查看源碼得知這個(gè)值是為4
//private static final int DEFAULT_NETWORK_THREAD_POOL_SIZE = 4;
mDelivery = delivery;
//這里傳進(jìn)來的是
//new ExecutorDelivery(new Handler(Looper.getMainLooper())));
//這里做的是,將子線程切換到主線程
}
我們最終是初始化了以上這些類,我們點(diǎn)擊NetworkDispatcher進(jìn)去看一下,里面做了一些什么事情
發(fā)現(xiàn)NetworkDispatcher是繼承了Thread類的,就說明,上面初始化的時(shí)候,初始化了4個(gè)線程.
RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir), network);
queue.start();
可以看出RequestQueue初始化做了一下事情:
- 初始化磁盤緩存
- 初始化了網(wǎng)絡(luò)連接
- 創(chuàng)建了4個(gè)網(wǎng)絡(luò)線程
- 初始化了一個(gè)將執(zhí)行結(jié)果發(fā)送到主線程的傳遞器
繼續(xù)點(diǎn)擊進(jìn)去看start方法做了什么事情
public void start() {
stop(); // Make sure any currently running dispatchers are stopped.
// Create the cache dispatcher and start it.
//首先創(chuàng)建了緩存分發(fā)器
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();
}
}
通過這個(gè)方法我們可以知道,首先創(chuàng)建了緩存分發(fā)器.首先檢查緩存中是否有數(shù)據(jù),我們進(jìn)去CacheDispatcher類查看
這是一個(gè)繼承了Thread的類,
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.
final Request<?> request = mCacheQueue.take(); //這里不斷地往緩存隊(duì)列中拿數(shù)據(jù)
request.addMarker("cache-queue-take"); //并且為請(qǐng)求添加標(biāo)記
// If the request has been canceled, don't bother dispatching it.
if (request.isCanceled()) { //判斷請(qǐng)求是否已經(jīng)取消
request.finish("cache-discard-canceled");
continue;
}
// Attempt to retrieve this item from cache.
Cache.Entry entry = mCache.get(request.getCacheKey());
//內(nèi)存中找不到請(qǐng)求,就從磁盤中查找緩存
if (entry == null) { //如果找不到緩存
request.addMarker("cache-miss"); //則為這個(gè)請(qǐng)求打上"緩存丟失的標(biāo)記"
// Cache miss; send off to the network dispatcher.
mNetworkQueue.put(request); //找不到緩存,就會(huì)往網(wǎng)絡(luò)隊(duì)列中尋找緩存
continue;
}
// If it is completely expired, just send it to the network.
if (entry.isExpired()) { //判斷緩存是否過期
request.addMarker("cache-hit-expired"); //過期了就,為緩存打上"緩存過期" 的標(biāo)記
request.setCacheEntry(entry); //并重新設(shè)置緩存
mNetworkQueue.put(request); //向網(wǎng)絡(luò)請(qǐng)求隊(duì)列中加入緩存
continue;
}
// We have a cache hit; parse its data for delivery back to the request.
request.addMarker("cache-hit"); //如果有緩存,就打上"找到緩存"的標(biāo)記
Response<?> response = request.parseNetworkResponse(
new NetworkResponse(entry.data, entry.responseHeaders));
//讀取緩存并解析緩存
request.addMarker("cache-hit-parsed"); //為請(qǐng)求打上"緩存被解析"的標(biāo)記
if (!entry.refreshNeeded()) {//判斷數(shù)據(jù)是否需要刷新
// Completely unexpired cache hit. Just deliver the response.
mDelivery.postResponse(request, response); //傳遞器將響應(yīng)從子線程傳遞到主線程
} else {
//如果數(shù)據(jù)需要重新刷新,就需要重新加入網(wǎng)絡(luò)請(qǐng)求隊(duì)列中,發(fā)送網(wǎng)絡(luò)請(qǐng)求
// 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;
// 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;
}
}
}
看完這里,可以知道,首先在內(nèi)存中尋找緩存,如果沒有就到磁盤中尋找緩存,如果沒有,再發(fā)送網(wǎng)絡(luò)請(qǐng)求獲取數(shù)據(jù).
和上面這個(gè)圖的工作原理一樣.數(shù)據(jù)加入網(wǎng)絡(luò)請(qǐng)求隊(duì)列之后,繼續(xù)往下看
for (int i = 0; i < mDispatchers.length; i++) {
NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork,
mCache, mDelivery);
mDispatchers[i] = networkDispatcher;
networkDispatcher.start();
}
這里添加了四個(gè)線程給網(wǎng)絡(luò)分發(fā)器,對(duì)應(yīng)上圖.
我們進(jìn)去NetworkDispatcher里面看
public void run() {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
while (true) {
long startTimeMs = SystemClock.elapsedRealtime();
Request<?> request;
try {
// Take a request from the queue.
request = mQueue.take();
} catch (InterruptedException e) {
// We may have been interrupted because it was time to quit.
if (mQuit) {
return;
}
continue;
}
try {
request.addMarker("network-queue-take");
// If the request was cancelled already, do not perform the
// network request.
if (request.isCanceled()) {
request.finish("network-discard-cancelled");
continue;
}
addTrafficStatsTag(request);
// Perform the network request.
NetworkResponse networkResponse = mNetwork.performRequest(request);
request.addMarker("network-http-complete");
// If the server returned 304 AND we delivered a response already,
// we're done -- don't deliver a second identical response.
if (networkResponse.notModified && request.hasHadResponseDelivered()) {
request.finish("not-modified");
continue;
}
// Parse the response here on the worker thread.
Response<?> response = request.parseNetworkResponse(networkResponse);
request.addMarker("network-parse-complete");
// Write to cache if applicable.
// TODO: Only update cache metadata instead of entire record for 304s.
if (request.shouldCache() && response.cacheEntry != null) {
mCache.put(request.getCacheKey(), response.cacheEntry);
request.addMarker("network-cache-written");
}
// Post the response back.
request.markDelivered();
mDelivery.postResponse(request, response); //發(fā)送響應(yīng)到主線程
} catch (VolleyError volleyError) {
volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs);
parseAndDeliverNetworkError(request, volleyError);
} catch (Exception e) {
VolleyLog.e(e, "Unhandled exception %s", e.toString());
VolleyError volleyError = new VolleyError(e);
volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs);
mDelivery.postError(request, volleyError);
}
}
}
工作原理和上面的緩存隊(duì)列工作原理相似.
mDelivery.postResponse(request, response); //發(fā)送響應(yīng)到主線程
繼續(xù)往下查看
@Override
public void postResponse(Request<?> request, Response<?> response, Runnable runnable) {
request.markDelivered();
request.addMarker("post-response");
mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, runnable));
}
這里執(zhí)行了ResponseDeliveryRunnable,繼續(xù)查看
public void run() {
// If this request has canceled, finish it and don't deliver.
if (mRequest.isCanceled()) {
mRequest.finish("canceled-at-delivery");
return;
}
// Deliver a normal response or error, depending.
if (mResponse.isSuccess()) { //響應(yīng)成功
mRequest.deliverResponse(mResponse.result);
} else { //響應(yīng)失敗
mRequest.deliverError(mResponse.error);
}
// If this is an intermediate response, add a marker, otherwise we're done
// and the request can be finished.
if (mResponse.intermediate) {
mRequest.addMarker("intermediate-response");
} else {
mRequest.finish("done");
}
// If we have been provided a post-delivery runnable, run it.
if (mRunnable != null) {
mRunnable.run();
}
}
響應(yīng)成功或者失敗都會(huì)回調(diào)監(jiān)聽
響應(yīng)成功:
@Override
protected void deliverResponse(T response) {
mListener.onResponse(response);
}
響應(yīng)失敗:
public void deliverError(VolleyError error) {
if (mErrorListener != null) {
mErrorListener.onErrorResponse(error);
}
}
因?yàn)楸救诉@里是使用JsonRequest,所以這里會(huì)響應(yīng)JsonRequest的請(qǐng)求,監(jiān)聽器就有數(shù)據(jù)過來了
private NetWorkListener<NewsListBean> mListener=new NetWorkListener<NewsListBean>()
{
@Override
public void onResponse(NewsListBean response) {
//保存新聞列表數(shù)據(jù)
mNews = response.getData().getNews();
//保存輪播圖數(shù)據(jù)
mTopNews = response.getData().getTopnews();
//刷新新聞列表
mAdapter.notifyDataSetChanged();
//保存more字段,加載更多
mMore = response.getData().getMore();
List<String> urls = new ArrayList<String>();
mTopNews = response.getData().getTopnews();
//遍歷輪播圖的數(shù)據(jù),構(gòu)建圖片url集合
for (int i = 0; i <mTopNews.size() ; i++) {
urls.add(mTopNews.get(i).getTopimage());
}
//刷新輪播圖
mFunBanner.setImageUrls(urls);//內(nèi)部使用glide加載圖片
}
};
NetWorkListener是我自己寫的,實(shí)現(xiàn)了Response.Listener,Response.ErrorListener接口
public class NetWorkListener<T> implements Response.Listener<T>,Response.ErrorListener{
@Override
public void onErrorResponse(VolleyError error) {
}
@Override
public void onResponse(T response) {
}
}