Volley is an HTTP library that makes networking for Android apps easier and most importantly, faster.
Volley是Google在2013年推出來(lái)的HTTP庫(kù),旨在幫助開(kāi)發(fā)者更快更簡(jiǎn)便的實(shí)現(xiàn)網(wǎng)絡(luò)請(qǐng)求。說(shuō)說(shuō)為什么要分析Volley的源碼吧,因?yàn)閂olley中線程的轉(zhuǎn)換時(shí)通過(guò) Thread 和 Handler 來(lái)實(shí)現(xiàn)的,跟之前的兩篇都有著很大的聯(lián)系(ps:Okhttp和Retrofit都撕不動(dòng)^_^),哈哈,后面會(huì)一步一步的給大家?guī)?lái)Okhttp和Retrofit等更多的源碼分析!
執(zhí)行一個(gè)網(wǎng)絡(luò)請(qǐng)求我們先整體看下 Volley 是如何進(jìn)行一個(gè)完整的網(wǎng)絡(luò)請(qǐng)求的:
val requestQueue: RequestQueue = Volley.newRequestQueue(context)
val url = "https://www.baidu.com"
val request = StringRequest(url,
Response.Listener {
Log.d("taonce", "request result is: $it")
},
Response.ErrorListener { })
requestQueue.add(request)
上面代碼主要做了三件事:
創(chuàng)建一個(gè)請(qǐng)求隊(duì)列 RequestQueue : Volley.newRequestQueue(context)
創(chuàng)建一個(gè)請(qǐng)求 Request : StringRequest(String url, Listener
將 Request 加入到 RequestQueue : requestQueue.add(request)
接下來(lái)通過(guò)源碼的方法來(lái)看看這三步內(nèi)部做了什么操作。
創(chuàng)建 RequestQueue 和 Request進(jìn)入 Volley.newRequestQueue(context) 源碼:public static RequestQueue newRequestQueue(Context context) {
// 實(shí)際上是調(diào)用了另外一個(gè)構(gòu)造方法
return newRequestQueue(context, (BaseHttpStack) null);
}
BasicNetwork network;
if (stack == null) {
// 判斷是否大于等于 Android 2.3 版本
if (Build.VERSION.SDK_INT >= 9) {
// 如果是 Android 2.3 及其以上,就用 HurlStack() 進(jìn)行網(wǎng)絡(luò)請(qǐng)求
network = new BasicNetwork(new HurlStack());
} else {
// 如果是 Android 2.3 以下,那么就采用 HttpClientStack(HttpClient) 進(jìn)行網(wǎng)絡(luò)請(qǐng)求
network = new BasicNetwork(
new HttpClientStack(AndroidHttpClient.newInstance(userAgent)));
}
} else {
// 如果stack不為空,那么就采用傳進(jìn)來(lái)的stack
network = new BasicNetwork(stack);
}
return newRequestQueue(context, network);
可以得出:
創(chuàng)建一個(gè) BasicNetwork 對(duì)象
stack 為空 ----> Android 2.3 及其以上創(chuàng)建 HurlStack() 對(duì)象,并且傳給 network,HurlStack() 采用的是 HttpURLConnetion 進(jìn)行網(wǎng)絡(luò)請(qǐng)求的。
stack 為空 ----> Android 2.3 以下創(chuàng)建 HttpClientStack() 對(duì)象,并且傳給 network,HttpClientStack() 采用的則是 HttpClient 進(jìn)行網(wǎng)絡(luò)請(qǐng)求,不過(guò)現(xiàn)在( 當(dāng)前版本1.1.1 ) new HttpClientStack(HttpClient client) 已經(jīng)被標(biāo)記了 @Deprecated 了,因?yàn)樗捎玫?HttpClient ,Google 在 Android 6.0 中移除了對(duì) Apache HTTP 客戶端的支持,并且從 Android P 開(kāi)始,org.apache.legacy 庫(kù)將從 bootclasspath 中刪除。
stack 不為空 ----> 直接將 stack 傳給 network
創(chuàng)建一個(gè) RequestQueue() 對(duì)象并返回
到此為止,大家只要記住上面幾個(gè)對(duì)象就好,接下來(lái)會(huì)慢慢的講解對(duì)象分別做了什么工作。
private static RequestQueue newRequestQueue(Context context, Network network) {
File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR);
// 創(chuàng)建請(qǐng)求隊(duì)列
RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir), network);
queue.start();
return queue;
}
public RequestQueue(Cache cache, Network network) {
// 默認(rèn) Network Thread 數(shù)目為 DEFAULT_NETWORK_THREAD_POOL_SIZE = 4
this(cache, network, DEFAULT_NETWORK_THREAD_POOL_SIZE);
}
public RequestQueue(Cache cache, Network network, int threadPoolSize) {
this(
cache,
network,
threadPoolSize,
// 注意點(diǎn)就是這:創(chuàng)建 Handler 的時(shí)候,傳遞的是 Looper.getMainLooper(),也就是后面將請(qǐng)求結(jié)果回調(diào)到主線程的關(guān)鍵。
new ExecutorDelivery(new Handler(Looper.getMainLooper())));
}
public RequestQueue(
Cache cache, Network network, int threadPoolSize, ResponseDelivery delivery) {
mCache = cache;
mNetwork = network;
mDispatchers = new NetworkDispatcher[threadPoolSize];
mDelivery = delivery;
}
上面第二個(gè)構(gòu)造方法中創(chuàng)建了一個(gè) ExecutorDelivery() , 這個(gè)對(duì)象實(shí)現(xiàn)了 ResponseDelivery 接口的類,用來(lái)將網(wǎng)絡(luò)請(qǐng)求的結(jié)果或者緩存中的結(jié)果分發(fā)到主線程。
// 開(kāi)啟5個(gè)線程
public void start() {
// 如果5個(gè)線程不為空,先停止它們
stop();
// 創(chuàng)建 CacheDispatcher,并開(kāi)啟它
mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery);
mCacheDispatcher.start();
// 創(chuàng)建4個(gè)NetworkDispatcher,并開(kāi)啟它們
for (int i = 0; i < mDispatchers.length; i++) {
NetworkDispatcher networkDispatcher =
new NetworkDispatcher(mNetworkQueue, mNetwork, mCache, mDelivery);
mDispatchers[i] = networkDispatcher;
networkDispatcher.start();
}
}
到此,我們前奏分析完了,有一些概念先不急著看,只要知道它的作用就行,后面我們來(lái)一個(gè)一個(gè)擊破。
添加請(qǐng)求到請(qǐng)求隊(duì)列中 : RequestQueue.add( request )廢話不多了,直接進(jìn)入源碼:RequestQueue.add(request)
public Request add(Request request) {
// 將request和當(dāng)前的RequestQueue綁定
request.setRequestQueue(this);
// 將request添加到set集合中,用于執(zhí)行 cancelAll() 操作
synchronized (mCurrentRequests) {
mCurrentRequests.add(request);
}
// 給request添加一些標(biāo)記
request.setSequence(getSequenceNumber());
request.addMarker("add-to-queue");
sendRequestEvent(request, RequestEvent.REQUEST_QUEUED);
// 判斷request是否需要緩存,對(duì)于 Get 以外的請(qǐng)求,默認(rèn)關(guān)閉緩存
if (!request.shouldCache()) {
mNetworkQueue.add(request);
return request;
}
mCacheQueue.add(request);
return request;
}
添加 request 的操作算是很簡(jiǎn)單的了,無(wú)非是根據(jù) request 是否需要緩存,將 request 添加到 CacheQueue 或者 NetworkQueue 中。
看到這,我們是不是在想,怎么添加之后就沒(méi)有動(dòng)作了?非也非也,我們回顧下,在創(chuàng)建 requestQueue 的同時(shí),是不是創(chuàng)建了5個(gè)子線程并且開(kāi)啟了它們,它們內(nèi)部使用的 CacheQueue 或者 NetworkQueue 不就是上面提到的么。接下來(lái),我們先看看 CacheDispatcher 內(nèi)部做了什么。
CacheDispatcher 調(diào)度器剖析:CacheDispatcher 就是一個(gè)繼承了 Thread 的類,我們?cè)趫?zhí)行 RequestQueue.start() 的時(shí)候創(chuàng)建了它,并開(kāi)啟了它,現(xiàn)在我們來(lái)看看它的 run() 方法:
@Override
public void run() {
// 設(shè)置線程優(yōu)先級(jí)為后臺(tái)線程
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
// 實(shí)則是執(zhí)行了DiskBasedCache的initialize()方法
mCache.initialize();
while (true) {
try {
processRequest();
} catch (InterruptedException e) {
// 中斷當(dāng)前線程,并且退出死循環(huán),mQuit在調(diào)用CacheDispatcher的quit()方法之后會(huì)被賦值為true
if (mQuit) {
Thread.currentThread().interrupt();
return;
}
}
}
}
開(kāi)了一個(gè)死循環(huán),然后調(diào)用了 processRequest() , 我們接著看這個(gè)方法:
private void processRequest() throws InterruptedException {
// 從CacheQueue中取出一個(gè)可用的request
final Request<);@VisibleForTesting
void processRequest(final Request<); throws InterruptedException {
request.addMarker("cache-queue-take");
request.sendEvent(RequestQueue.RequestEvent.REQUEST_CACHE_LOOKUP_STARTED);
try {
//request如果被取消了,就直接返回
if (request.isCanceled()) {
request.finish("cache-discard-canceled");
return;
}
Cache.Entry entry = mCache.get(request.getCacheKey());
// 沒(méi)有緩存就把request添加到NetworkQueue中
if (entry == null) {
request.addMarker("cache-miss");
// 沒(méi)有緩存,并且等待隊(duì)列中也沒(méi)有此request,那么就直接加入到NetworkQueue中
if (!mWaitingRequestManager.maybeAddToWaitingRequests(request)) {
mNetworkQueue.put(request);
}
return;
}
// 如果緩存過(guò)期了,也是一樣把request添加到NetworkQueue中
if (entry.isExpired()) {
request.addMarker("cache-hit-expired");
request.setCacheEntry(entry);
if (!mWaitingRequestManager.maybeAddToWaitingRequests(request)) {
mNetworkQueue.put(request);
}
return;
}
// 有緩存并且沒(méi)有過(guò)期
request.addMarker("cache-hit");
// 根據(jù)緩存的內(nèi)容解析
Response<);new NetworkResponse(entry.data, entry.responseHeaders));
request.addMarker("cache-hit-parsed");
// 是否需要更新
if (!entry.refreshNeeded()) {
// 不需要更新,直接將結(jié)果調(diào)度到主線程
mDelivery.postResponse(request, response);
} else {
request.addMarker("cache-hit-refresh-needed");
request.setCacheEntry(entry);
response.intermediate = true;
// 判斷是否有相同緩存鍵的任務(wù)在執(zhí)行
if (!mWaitingRequestManager.maybeAddToWaitingRequests(request)) {
// 需要更新結(jié)果,先將結(jié)果調(diào)度到主線程,然后執(zhí)行new runnable(){}
// runnable中就是將request添加到NetworkQueue中,更新一下內(nèi)容
mDelivery.postResponse(
request,
response,
new Runnable() {
@Override
public void run() {
try {
mNetworkQueue.put(request);
} catch (InterruptedException e) {
// Restore the interrupted status
Thread.currentThread().interrupt();
}
}
});
} else {
// request已經(jīng)加入到mWaitingRequests中
// 直接把結(jié)果調(diào)度到主線程
mDelivery.postResponse(request, response);
}
}
} finally {
request.sendEvent(RequestQueue.RequestEvent.REQUEST_CACHE_LOOKUP_FINISHED);
}
}
我們?cè)?processRequest 中可以看到有一個(gè)方法經(jīng)常出現(xiàn),那就是 mWaitingRequestManager.maybeAddToWaitingRequests(request) ,它的作用是判斷當(dāng)前這個(gè) request 是否有存在相同緩存鍵的請(qǐng)求已經(jīng)處于運(yùn)行狀態(tài),如果有,那么就將這個(gè) request 加入到一個(gè)等待隊(duì)列中,等到相同緩存鍵的請(qǐng)求完成。
總結(jié)一下 CacheDispatcher 主要步驟:
從 CacheQueue 中循環(huán)取出 request;
如果緩存丟失,加入到 NetworkQueue 中;
如果緩存過(guò)期,加入到 NetworkQueue 中;
將緩存中的數(shù)據(jù)解析成 Response 對(duì)象;
如果不需要更新,直接將結(jié)果回調(diào)到主線程,回調(diào)操作等介紹完NetworkDispatcher之后一起深入剖析;
如果需要更新,先將結(jié)果回調(diào)到主線程,然后再將 request 加入到 NetworkQueue 中。
NetworkDispatcher 調(diào)度器剖析:NetworkDispatcher 和 CacheDispatcher 十分類似,都是 Thread 的子類,下面重點(diǎn)看下它的 run() 方法:
@Override
public void run() {
// 設(shè)置線程優(yōu)先級(jí)為后臺(tái)線程
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
while (true) {
try {
processRequest();
} catch (InterruptedException e) {
// 調(diào)用quit()方法之后,mQuit就會(huì)被賦值true
if (mQuit) {
Thread.currentThread().interrupt();
return;
}
}
}
}
繼續(xù)看 processRequest() 方法:
private void processRequest() throws InterruptedException {
// 從NetworkQueue中取出request
Request<);@VisibleForTesting
void processRequest(Request<); {
long startTimeMs = SystemClock.elapsedRealtime();
request.sendEvent(RequestQueue.RequestEvent.REQUEST_NETWORK_DISPATCH_STARTED);
try {
request.addMarker("network-queue-take");
// 如果request被取消了,那么就不執(zhí)行此request
if (request.isCanceled()) {
request.finish("network-discard-cancelled");
request.notifyListenerResponseNotUsable();
return;
}
addTrafficStatsTag(request);
// 還記得這個(gè)mNetwork么,它就是Volley.newRequestQueue()方法里的BasicNetwork對(duì)象,一會(huì)我們來(lái)看看mNetwork.performRequest()方法是如何得到NetworkResponse的
NetworkResponse networkResponse = mNetwork.performRequest(request);
request.addMarker("network-http-complete");
// notModified是服務(wù)端返回304,hasHadResponseDelivered()是request已經(jīng)回調(diào)過(guò)了
if (networkResponse.notModified && request.hasHadResponseDelivered()) {
request.finish("not-modified");
request.notifyListenerResponseNotUsable();
return;
}
// 將NetworkResponse解析成Response對(duì)象,在子線程中執(zhí)行
Response<);"network-parse-complete");
// 將request寫(xiě)入緩存
if (request.shouldCache() && response.cacheEntry != null) {
mCache.put(request.getCacheKey(), response.cacheEntry);
request.addMarker("network-cache-written");
}
request.markDelivered();
// 回調(diào)結(jié)果至主線程
mDelivery.postResponse(request, response);
request.notifyListenerResponseReceived(response);
}
// 以下都是處理異常錯(cuò)誤,然后也需要回調(diào)至主線程
catch (VolleyError volleyError) {
volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs);
parseAndDeliverNetworkError(request, volleyError);
request.notifyListenerResponseNotUsable();
} 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);
request.notifyListenerResponseNotUsable();
} finally {
request.sendEvent(RequestQueue.RequestEvent.REQUEST_NETWORK_DISPATCH_FINISHED);
}
}
通過(guò) NetworkDispatcher.run() 方法可以發(fā)現(xiàn),主要分為以下幾步:
通過(guò) BasicNetwork.performRequest(request) 得到 NetworkResponse 對(duì)象;
通過(guò) request.parseNetworkResponse(networkResponse) 解析得到 Response 對(duì)象;
通過(guò) mDelivery 將成功結(jié)果或者失敗結(jié)果回調(diào)到主線程。
現(xiàn)在我們依次來(lái)分析下這三步:
請(qǐng)求網(wǎng)絡(luò),得到 NetworkResponse:
BasicNetwork 實(shí)現(xiàn)了 Network 接口,其主要代碼集中在 NetworkResponse performRequest(Request<); 中,也就是執(zhí)行特定的請(qǐng)求。
@Override
public NetworkResponse performRequest(Request<); throws VolleyError {
long requestStart = SystemClock.elapsedRealtime();
while (true) {
HttpResponse httpResponse = null;
byte[] responseContents = null;
List responseHeaders = Collections.emptyList();
try {
// 得到請(qǐng)求頭信息
Map additionalRequestHeaders =
getCacheHeaders(request.getCacheEntry());
// 具體的網(wǎng)絡(luò)請(qǐng)求是靠BaseHttpStack執(zhí)行的
httpResponse = mBaseHttpStack.executeRequest(request, additionalRequestHeaders);
int statusCode = httpResponse.getStatusCode();
responseHeaders = httpResponse.getHeaders();
// 下面就是根據(jù)不同的狀態(tài)碼返回不同的NetworkResponse對(duì)象了,具體就不分析了
if (statusCode == HttpURLConnection.HTTP_NOT_MODIFIED) {
Entry entry = request.getCacheEntry();
if (entry == null) {
return new NetworkResponse(
HttpURLConnection.HTTP_NOT_MODIFIED,
/* data= */ null,
/* notModified= */ true,
SystemClock.elapsedRealtime() - requestStart,
responseHeaders);
}
}
// 省略大部分代碼...
}
通過(guò)上面源碼可以看出,BasicNetwork 就是封裝了一下 NetworkResponse 對(duì)象蠻,并沒(méi)有涉及到網(wǎng)絡(luò)請(qǐng)求,我們繼續(xù)深入到 BaseHttpStack.executeRequest(request, additionalRequestHeaders) 源碼中。
public abstract class BaseHttpStack implements HttpStack {
public abstract HttpResponse executeRequest(
Request<);
throws IOException, AuthFailureError;
}
我們發(fā)現(xiàn) BaseHttpStack 是一個(gè)抽象類,那么具體的請(qǐng)求是在哪呢,不知道你是否還有印象,在Volley.newRequestQueue() 中,我們創(chuàng)建 BasicNetwork 的時(shí)候是根據(jù) Android 版本傳入不同的 BaseHttpStack 子類,Android 2.3 以上我們傳入的是 HurlStack 對(duì)象,下面就看看 HurlStack.executeRequest() 方法吧。
@Override
public HttpResponse executeRequest(Request<);
throws IOException, AuthFailureError {
// 得到url
String url = request.getUrl();
HashMap map = new HashMap<>();
map.putAll(additionalHeaders);
// Request.getHeaders() takes precedence over the given additional (cache) headers).
map.putAll(request.getHeaders());
...
URL parsedUrl = new URL(url);
// 通過(guò)HttpURLConnection來(lái)請(qǐng)求網(wǎng)絡(luò)
HttpURLConnection connection = openConnection(parsedUrl, request);
}
其實(shí) HurlStack.executeRequest() 方法里,就是借助了 HttpURLConnection 對(duì)象來(lái)請(qǐng)求網(wǎng)絡(luò),并根據(jù)不同的條件返回不同的 HttpResponse 對(duì)象的。
解析 NetworkResponse , 得到 Response :
解析過(guò)程是定義在 Request 抽象類的 protected abstract Response
@Override
@SuppressWarnings("DefaultCharset")
protected Response parseNetworkResponse(NetworkResponse response) {
String parsed;
try {
// 將response中的data信息取出來(lái)
parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
} catch (UnsupportedEncodingException e) {
// Since minSdkVersion = 8, we cant call
// new String(response.data, Charset.defaultCharset())
// So suppress the warning instead.
parsed = new String(response.data);
}
// 封裝成Response對(duì)象
return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response));
}
回調(diào)主線程,如果你看過(guò)我之前的 Handler源碼剖析 文章話,那么這一步就很簡(jiǎn)單了,我們來(lái)理一理:
回調(diào)是通過(guò) ResponseDelivery mDelivery 對(duì)象來(lái)執(zhí)行的,這個(gè)對(duì)象最早是在創(chuàng)建 RequestQueue() 的時(shí)候初始化的,我在那一小節(jié)特意標(biāo)注了,再來(lái)回顧下:
public RequestQueue(Cache cache, Network network, int threadPoolSize) {
this(
cache,
network,
threadPoolSize,
// 創(chuàng)建ExecutorDelivery對(duì)象,傳入一個(gè)Handler對(duì)象,并且Handler綁定的是主線程的Looper
new ExecutorDelivery(new Handler(Looper.getMainLooper())));
}
public class ExecutorDelivery implements ResponseDelivery {
private final Executor mResponsePoster;
/**
* ExecutorDelivery構(gòu)造函數(shù),內(nèi)部初始化了mResponsePoster接口
* 并且在execute()方法里調(diào)用了handler.post()方法
*/
public ExecutorDelivery(final Handler handler) {
// 初始化Execute對(duì)象
mResponsePoster =
new Executor() {
@Override
public void execute(Runnable command) {
handler.post(command);
}
};
}
}
知道了它的初始化,我們?cè)賮?lái)看看它是如何實(shí)現(xiàn)回調(diào)的:
Volley 中回調(diào)是通過(guò)postResponse()方法的 :
public void postResponse(Request<);"post-response"); mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, runnable)); }
postResponse() 最終會(huì)調(diào)用 mResponsePoster 對(duì)象的 execute() 方法,傳入了一個(gè) ResponseDeliveryRunnable 對(duì)象,它實(shí)現(xiàn)了 Runnable 接口,execute() 方法會(huì)通過(guò) Handler.post(runnable) 將 ResponseDeliveryRunnable 放入消息隊(duì)列。最后我們來(lái)看看這個(gè) ResponseDeliveryRunnable 的 run() 方法在主線程中做了什么操作:
@SuppressWarnings("unchecked")
@Override
public void run() {
// If this request has canceled, finish it and dont deliver.
if (mRequest.isCanceled()) {
mRequest.finish("canceled-at-delivery");
return;
}
if (mResponse.isSuccess()) {
// 執(zhí)行成功的回調(diào),在具體的Request實(shí)現(xiàn)類中,比如StringRequest就會(huì)調(diào)用listener.onResponse(string)回調(diào)
mRequest.deliverResponse(mResponse.result);
} else {
// 執(zhí)行失敗的回調(diào),在request中,直接回調(diào)了listener.onErrorResponse(error)
mRequest.deliverError(mResponse.error);
}
// intermediate默認(rèn)為false,但是在CacheDispatcher的run()中,如果需要更新緩存,那么就會(huì)置為true
if (mResponse.intermediate) {
mRequest.addMarker("intermediate-response");
} else {
mRequest.finish("done");
}
// 如果傳入了runnable不為空,那就就執(zhí)行runnable.run()方法
// 回憶下在CacheDispatcher的run()方法中,如果request有緩存,但是需要更新緩存的時(shí)候,mDelivery是不是調(diào)用的帶runnable的方法
if (mRunnable != null) {
mRunnable.run();
}
}
分析到這的時(shí)候,大家可以借助下方的流程圖理一理Volley的整體流程,主要理解一下緩存線程和網(wǎng)絡(luò)線程的轉(zhuǎn)換,子線程和主線程的轉(zhuǎn)換:
源碼分析的文字還在不斷的更新,如果本文章你發(fā)現(xiàn)的不正確或者不足之處,歡迎你在下方留言或者掃描下方的二維碼留言也可!
掃描關(guān)注公眾號(hào)
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/7060.html
摘要:接下來(lái)看看網(wǎng)絡(luò)調(diào)度線程。讓我們?cè)倩氐?,?qǐng)求網(wǎng)絡(luò)后,會(huì)將響應(yīng)結(jié)果存在緩存中,如果響應(yīng)結(jié)果成功則調(diào)用來(lái)回調(diào)給主線程。我們用請(qǐng)求網(wǎng)絡(luò)的寫(xiě)法是這樣的將請(qǐng)求添加在請(qǐng)求隊(duì)列中看到第行整個(gè)的大致流程都通了吧,好了關(guān)于的源碼就講到這里。 1.Volley結(jié)構(gòu)圖 showImg(https://segmentfault.com/img/remote/1460000011351317); 從上圖可以看到V...
摘要:在大行其道的今天,已經(jīng)略顯過(guò)時(shí)。我們按照上面的思路,從和作為出發(fā)點(diǎn),由淺入深來(lái)閱讀源碼。在最后看類源碼時(shí)我們可以看到這個(gè)過(guò)程。負(fù)責(zé)分發(fā),對(duì)來(lái)說(shuō),就是通過(guò)將發(fā)送到了主線程在中調(diào)用了。的個(gè)數(shù),決定了網(wǎng)絡(luò)請(qǐng)求的最大并發(fā)數(shù)。 Volley 在 retrofit+okhttp 大行其道的今天,volley 已經(jīng)略顯過(guò)時(shí)。使用 volley,我們無(wú)法避免寫(xiě)一些樣板代碼,但在它剛出現(xiàn)時(shí),曾經(jīng)很大程度...
閱讀 736·2023-04-25 19:43
閱讀 3981·2021-11-30 14:52
閱讀 3807·2021-11-30 14:52
閱讀 3871·2021-11-29 11:00
閱讀 3802·2021-11-29 11:00
閱讀 3904·2021-11-29 11:00
閱讀 3580·2021-11-29 11:00
閱讀 6184·2021-11-29 11:00