您好,登錄后才能下訂單哦!
本篇文章給大家分享的是有關(guān)如何Android Volley庫(kù)中HTTP Request部分的源碼分析,小編覺(jué)得挺實(shí)用的,因此分享給大家學(xué)習(xí),希望大家閱讀完這篇文章后可以有所收獲,話不多說(shuō),跟著小編一起來(lái)看看吧。
目源碼的目錄樹(shù):
[android] ┗━[volley] ┣━AuthFailureError.java ┣━Cache.java ┣━CacheDispatcher.java ┣━DefaultRetryPolicy.java ┣━ExecutorDelivery.java ┣━InternalUtils.java ┣━Network.java ┣━NetworkDispatcher.java ┣━NetworkError.java ┣━NetworkResponse.java ┣━NoConnectionError.java ┣━ParseError.java ┣━RedirectError.java ┣━Request.java ┣━RequestQueue.java ┣━Response.java ┣━ResponseDelivery.java ┣━RetryPolicy.java ┣━ServerError.java ┣━TimeoutError.java ┣━[toolbox] ┃ ┣━AndroidAuthenticator.java ┃ ┣━Authenticator.java ┃ ┣━BasicNetwork.java ┃ ┣━ByteArrayPool.java ┃ ┣━ClearCacheRequest.java ┃ ┣━DiskBasedCache.java ┃ ┣━HttpClientStack.java ┃ ┣━HttpHeaderParser.java ┃ ┣━HttpStack.java ┃ ┣━HurlStack.java ┃ ┣━ImageLoader.java ┃ ┣━ImageRequest.java ┃ ┣━JsonArrayRequest.java ┃ ┣━JsonObjectRequest.java ┃ ┣━JsonRequest.java ┃ ┣━NetworkImageView.java ┃ ┣━NoCache.java ┃ ┣━PoolingByteArrayOutputStream.java ┃ ┣━RequestFuture.java ┃ ┣━StringRequest.java ┃ ┗━Volley.java ┣━VolleyError.java ┗━VolleyLog.java
可以看出,Volley源碼放置得較為雜亂,不同功能模塊的類并沒(méi)有歸到不同的包中。相比之下UIL的源碼結(jié)構(gòu)較為規(guī)范和合理。
從常用case入手,推斷其項(xiàng)目架構(gòu)
官網(wǎng)上給出的最簡(jiǎn)單的使用例子如下所示:
final TextView mTextView = (TextView) findViewById(R.id.text);
// 1. 新建一個(gè)Queue RequestQueue queue = Volley.newRequestQueue(this); String url ="http://www.google.com"; // 2. 新建一個(gè)Request,寫(xiě)好listener StringRequest stringRequest = new StringRequest(Request.Method.GET, url, new Response.Listener<String>() { @Override public void onResponse(String response) { // Display the first 500 characters of the response string. mTextView.setText("Response is: "+ response.substring(0,500)); } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { mTextView.setText("That didn't work!"); } }); // 3. 將Request放到Queue里面執(zhí)行 queue.add(stringRequest); 結(jié)合下面這張圖: 架構(gòu)圖 我們可以大致了解Volley的使用方法(見(jiàn)注釋)和內(nèi)部結(jié)構(gòu)。下面就這個(gè)usecase展開(kāi)進(jìn)行源碼級(jí)別的簡(jiǎn)述。 Volley類 Volley類提供了4個(gè)靜態(tài)方法來(lái)方便用戶新建Queue。其中: public static RequestQueue newRequestQueue(Context context) { return newRequestQueue(context, null); } 一句最終會(huì)調(diào)用: // 傳入 context,stack=null,maxDiskCacheBytes=-1 public static RequestQueue newRequestQueue(Context context, HttpStack stack, int maxDiskCacheBytes) { File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR); String userAgent = "volley/0"; //1. 設(shè)置userAgent 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) { //2. 選擇用哪個(gè)httpclient stack = new HurlStack(); } else { // 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; if (maxDiskCacheBytes <= -1) { // No maximum size specified queue = new RequestQueue(new DiskBasedCache(cacheDir), network); //3. 新建Queue } else { // Disk cache size specified queue = new RequestQueue(new DiskBasedCache(cacheDir, maxDiskCacheBytes), network); } queue.start();// 4. 傳入Queue return queue; }
值得注意的是:
Volley會(huì)根據(jù)SDK的version來(lái)決定使用java.net.HttpURLConnection(Build.VERSION.SDK_INT >= 9)還是org.apache.http.client.HttpClient
新建Queue后,Queue馬上會(huì)被start。
stack類負(fù)責(zé)發(fā)送request(com.android.volley.Request)和獲取response(org.apache.http.HttpResponse),network類負(fù)責(zé)分析和處理response,包裝成NetworkResponse(com.android.volley.NetworkResponse)。 我們首先忽略掉network相關(guān)的細(xì)節(jié),看一下queue的實(shí)現(xiàn)和request的調(diào)度策略。 RequestQueue 先來(lái)看一下RequestQueue的構(gòu)造方法: public RequestQueue(Cache cache, Network network) { this(cache, network, DEFAULT_NETWORK_THREAD_POOL_SIZE); }
調(diào)用:
public RequestQueue(Cache cache, Network network, int threadPoolSize) { this(cache, network, threadPoolSize, new ExecutorDelivery(new Handler(Looper.getMainLooper()))); } 這里出現(xiàn)了一個(gè)新面孔ExecutorDelivery,根據(jù)字面意思可以猜測(cè)它是負(fù)責(zé)將請(qǐng)求的結(jié)果分發(fā)到主線程上,或者在主線程上執(zhí)行回調(diào)(listener)。繼續(xù)調(diào)用: public RequestQueue(Cache cache, Network network, int threadPoolSize, ResponseDelivery delivery) { mCache = cache; mNetwork = network; mDispatchers = new NetworkDispatcher[threadPoolSize]; mDelivery = delivery; }
這里又出現(xiàn)了一個(gè)新面孔NetworkDispatcher。留意到threadPoolSize這個(gè)數(shù)組長(zhǎng)度參數(shù)的字面意義,結(jié)合上面的Volley架構(gòu)圖,猜想NetworkDispatcher是一個(gè)work thread,循環(huán)等待并通過(guò)network執(zhí)行在Queue上的request。
RequestQueue被實(shí)例化后,便調(diào)用其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(); } } 相應(yīng)地有: public void stop() { if (mCacheDispatcher != null) { mCacheDispatcher.quit(); } for (int i = 0; i < mDispatchers.length; i++) { if (mDispatchers[i] != null) { mDispatchers[i].quit(); } } }
這里的邏輯很簡(jiǎn)單:
開(kāi)始之前停止所有舊的任務(wù)(即interrupt所有worker thread)。
啟動(dòng)一個(gè)負(fù)責(zé)cache的worker thread。
啟動(dòng)n個(gè)負(fù)責(zé)network的worker thread。
worker thread開(kāi)始不斷地等待來(lái)自Queue的request。
Request
接下來(lái)執(zhí)行queue.add(stringRequest); ,一個(gè)request被加入到queue中,代碼如下所示:
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. request.setRequestQueue(this); synchronized (mCurrentRequests) { mCurrentRequests.add(request); } // Process requests in the order they are added. request.setSequence(getSequenceNumber()); request.addMarker("add-to-queue"); // marker用來(lái)指示request當(dāng)前的狀態(tài),實(shí)際上是用來(lái)打log // If the request is uncacheable, skip the cache queue and go straight to the network. if (!request.shouldCache()) { mNetworkQueue.add(request); return request; } // 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; } }
這里的邏輯是:
對(duì)新加進(jìn)來(lái)的request進(jìn)行一些設(shè)置。
如果不需要cache,那么把request直接加到network queue中。
根據(jù)key檢查request是否正在執(zhí)行。如果是,則將其放入到waiting鏈表中。猜想當(dāng)request完成的時(shí)候會(huì)調(diào)用某個(gè)方法將key在waiting鏈表中刪除,然后依次執(zhí)行waiting的request。如果否,則將其加入cache queue中。
CacheDispatcher
假設(shè)該uri訪問(wèn)是***次執(zhí)行,那么對(duì)應(yīng)的request會(huì)被放到cache queue中。cache worker thread(cache dispatcher)發(fā)現(xiàn)cache queue中存在request,會(huì)馬上將其dequeue并執(zhí)行。我們來(lái)看一下CacheDispatcher的run方法:
public class CacheDispatcher extends Thread { private final Cache mCache; // 一開(kāi)始傳入了“new DiskBasedCache(cacheDir)” ... public void quit() { mQuit = true; interrupt(); } @Override 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(); Request<?> request; while (true) { // release previous request object to avoid leaking request object when mQueue is drained. request = null; //確保***一個(gè)request做完后能及時(shí)回收內(nèi)存。 try { // Take a request from the queue. request = mCacheQueue.take(); // 堵塞 } catch (InterruptedException e) { // We may have been interrupted because it was time to quit. if (mQuit) { return; // 退出點(diǎn) } continue; } try { request.addMarker("cache-queue-take"); // If the request has been canceled, don't bother dispatching it. if (request.isCanceled()) { request.finish("cache-discard-canceled"); continue; } // miss cache則直接將request放到network queue中 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; } // cache 過(guò)期了,直接將request放到network queue中 if (entry.isExpired()) { request.addMarker("cache-hit-expired"); request.setCacheEntry(entry); mNetworkQueue.put(request); continue; } // 將cache中的data包裝成一個(gè)response request.addMarker("cache-hit"); Response<?> response = request.parseNetworkResponse( new NetworkResponse(entry.data, entry.responseHeaders)); request.addMarker("cache-hit-parsed"); if (!entry.refreshNeeded()) { // cache不需要刷新,直接將response交給delivery mDelivery.postResponse(request, response); } else { // cache需要刷新?,F(xiàn)將舊的內(nèi)容返回,同時(shí)將request放進(jìn)network queue。 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. final Request<?> finalRequest = request; mDelivery.postResponse(request, response, new Runnable() { @Override public void run() { try { mNetworkQueue.put(finalRequest); } catch (InterruptedException e) { // Not much we can do about this. } } }); } } catch (Exception e) { VolleyLog.e(e, "Unhandled exception %s", e.toString()); } } } }
接下來(lái)看一下mDelivery.postResponse這個(gè)方法。
ExecutorDelivery
從上文得知,mDelivery是一個(gè)ExecutorDelivery的實(shí)例(在新建RequestQueue時(shí)傳入)。
ExecutorDelivery的初始化代碼如下所示:
public ExecutorDelivery(final Handler handler) { // Make an Executor that just wraps the handler. mResponsePoster = new Executor() { // java.util.concurrent.Executor; @Override public void execute(Runnable command) { handler.post(command); } }; }
關(guān)于java.util.concurrent.Executor可以看這篇文章,這里就不展開(kāi)了。
postResponse代碼如下所示:
@Override public void postResponse(Request<?> request, Response<?> response, Runnable runnable) { request.markDelivered(); //標(biāo)記為已分發(fā) request.addMarker("post-response"); mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, runnable)); // 在初始化時(shí)傳入的handler中執(zhí)行ResponseDeliveryRunnable } ResponseDeliveryRunnable是ExecutorDelivery的一個(gè)子類,負(fù)責(zé)根據(jù)request的不同結(jié)果調(diào)用對(duì)應(yīng)的listener方法: @SuppressWarnings("rawtypes") private class ResponseDeliveryRunnable implements Runnable { private final Request mRequest; private final Response mResponse; private final Runnable mRunnable; public ResponseDeliveryRunnable(Request request, Response response, Runnable runnable) { mRequest = request; mResponse = response; mRunnable = runnable; } @SuppressWarnings("unchecked") @Override public void run() { // 在主線程中執(zhí)行 // If this request has canceled, finish it and don't deliver. if (mRequest.isCanceled()) { mRequest.finish("canceled-at-delivery"); // 會(huì)調(diào)用 RequestQueue的finish方法 return; } // Deliver a normal response or error, depending. if (mResponse.isSuccess()) { mRequest.deliverResponse(mResponse.result); //調(diào)用 listener的onResponse(response) } else { 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(); } } }
接下來(lái)我們回頭看看NetworkDispatcher對(duì)network queue的處理。
NetworkDispatcher
NetworkDispatcher的源碼如下所示:
public class NetworkDispatcher extends Thread { private final Network mNetwork; // BasicNetwork實(shí)例 ... private final BlockingQueue<Request<?>> mQueue; // network queue ... public void quit() { mQuit = true; interrupt(); } @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) private void addTrafficStatsTag(Request<?> request) { // 方便統(tǒng)計(jì)Volley的網(wǎng)絡(luò)流量 ... } @Override public void run() { Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); Request<?> request; while (true) { long startTimeMs = SystemClock.elapsedRealtime(); // release previous request object to avoid leaking request object when mQueue is drained. request = null; try { //1. 堵塞讀取network queue中的request 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); //2. 在network對(duì)象中堵塞執(zhí)行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()) { // 304表示資源未被修改 request.finish("not-modified"); continue; } //3. 將NetworkResponse轉(zhuǎn)成Response 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) { // 4. Response放到cache中 mCache.put(request.getCacheKey(), response.cacheEntry); request.addMarker("network-cache-written"); } //5. 通過(guò)Delivery回調(diào)結(jié)果 request.markDelivered(); mDelivery.postResponse(request, response); } 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); } } } private void parseAndDeliverNetworkError(Request<?> request, VolleyError error) { error = request.parseNetworkError(error); mDelivery.postError(request, error); } }
NetworkDispatcher的處理流程和CacheDispatcher差不多,見(jiàn)注釋。TrafficStats的介紹可以看這里。
上述代碼的關(guān)鍵在于mNetwork.performRequest(request)和request.parseNetworkResponse(networkResponse)這兩個(gè)調(diào)用。
Network Network是一個(gè)接口,只有一個(gè)performRequest(Request<?> request)方法: public interface Network { public NetworkResponse performRequest(Request<?> request) throws VolleyError; }
本文例子中Network的實(shí)現(xiàn)類是BasicNetwork:
public class BasicNetwork implements Network { protected static final boolean DEBUG = VolleyLog.DEBUG; private static int SLOW_REQUEST_THRESHOLD_MS = 3000; private static int DEFAULT_POOL_SIZE = 4096; protected final HttpStack mHttpStack; protected final ByteArrayPool mPool; public BasicNetwork(HttpStack httpStack) { // If a pool isn't passed in, then build a small default pool that will give us a lot of // benefit and not use too much memory. this(httpStack, new ByteArrayPool(DEFAULT_POOL_SIZE)); } ... } 注意到BasicNetwork的兩個(gè)關(guān)鍵的成員:mHttpStack和mPool,和對(duì)apache依賴: import org.apache.http.Header; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; import org.apache.http.StatusLine;
可我們先來(lái)看一下performRequest()的執(zhí)行流程:
public NetworkResponse performRequest(Request<?> request) throws VolleyError { long requestStart = SystemClock.elapsedRealtime(); while (true) { // 依賴 org.apache.http.HttpResponse HttpResponse httpResponse = null; byte[] responseContents = null; Map<String, String> responseHeaders = Collections.emptyMap(); try { // 1. 生成header Map<String, String> headers = new HashMap<String, String>(); addCacheHeaders(headers, request.getCacheEntry()); // 2. 通過(guò)httpstack發(fā)起請(qǐng)求。注意‘發(fā)起請(qǐng)求’這個(gè)動(dòng)作不在request中進(jìn)行,request只是保存著請(qǐng)求的信息。 httpResponse = mHttpStack.performRequest(request, headers); // 3. 獲得請(qǐng)求結(jié)果的一些信息 StatusLine statusLine = httpResponse.getStatusLine(); int statusCode = statusLine.getStatusCode(); responseHeaders = convertHeaders(httpResponse.getAllHeaders()); // 4. 通過(guò)statusCode(304)來(lái)判斷是否可以直接使用cache if (statusCode == HttpStatus.SC_NOT_MODIFIED) { Entry entry = request.getCacheEntry(); if (entry == null) { return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED, null, responseHeaders, true, SystemClock.elapsedRealtime() - requestStart); } // 從cache中取出data,返回新的NetworkResponse entry.responseHeaders.putAll(responseHeaders); return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED, entry.data, entry.responseHeaders, true, SystemClock.elapsedRealtime() - requestStart); } // 5. 通過(guò)statusCode通過(guò)判斷是否需要重定向 if (statusCode == HttpStatus.SC_MOVED_PERMANENTLY || statusCode == HttpStatus.SC_MOVED_TEMPORARILY) { String newUrl = responseHeaders.get("Location"); request.setRedirectUrl(newUrl); } // 6. 取出reponse中的data,為字節(jié)數(shù)組 // Some responses such as 204s do not have content. We must check. if (httpResponse.getEntity() != null) { // 通過(guò)entityToBytes從outputstream中讀取數(shù)據(jù),throws IOException responseContents = entityToBytes(httpResponse.getEntity()); } else { // Add 0 byte response as a way of honestly representing a // no-content request. responseContents = new byte[0]; } // if the request is slow, log it. long requestLifetime = SystemClock.elapsedRealtime() - requestStart; logSlowRequests(requestLifetime, request, responseContents, statusLine); if (statusCode < 200 || statusCode > 299) { throw new IOException(); } return new NetworkResponse(statusCode, responseContents, responseHeaders, false, SystemClock.elapsedRealtime() - requestStart); } catch (SocketTimeoutException e) { attemptRetryOnException("socket", request, new TimeoutError()); } catch (ConnectTimeoutException e) { attemptRetryOnException("connection", request, new TimeoutError()); } catch (MalformedURLException e) { throw new RuntimeException("Bad URL " + request.getUrl(), e); } catch (IOException e) { // 7. 如果entityToBytes方法throw了IOException int statusCode = 0; NetworkResponse networkResponse = null; if (httpResponse != null) { statusCode = httpResponse.getStatusLine().getStatusCode(); } else { throw new NoConnectionError(e); } if (statusCode == HttpStatus.SC_MOVED_PERMANENTLY || statusCode == HttpStatus.SC_MOVED_TEMPORARILY) { VolleyLog.e("Request at %s has been redirected to %s", request.getOriginUrl(), request.getUrl()); } else { VolleyLog.e("Unexpected response code %d for %s", statusCode, request.getUrl()); } // 如果reponseContent有數(shù)據(jù) if (responseContents != null) { networkResponse = new NetworkResponse(statusCode, responseContents, responseHeaders, false, SystemClock.elapsedRealtime() - requestStart); // 那么根據(jù)statusCode執(zhí)行重試 if (statusCode == HttpStatus.SC_UNAUTHORIZED || statusCode == HttpStatus.SC_FORBIDDEN) { attemptRetryOnException("auth", request, new AuthFailureError(networkResponse)); } else if (statusCode == HttpStatus.SC_MOVED_PERMANENTLY || statusCode == HttpStatus.SC_MOVED_TEMPORARILY) { attemptRetryOnException("redirect", request, new RedirectError(networkResponse)); } else { // TODO: Only throw ServerError for 5xx status codes. throw new ServerError(networkResponse); } } else { throw new NetworkError(e); } } } }
attemptRetryOnException()代碼如下所示:
private static void attemptRetryOnException(String logPrefix, Request<?> request, VolleyError exception) throws VolleyError { RetryPolicy retryPolicy = request.getRetryPolicy(); int oldTimeout = request.getTimeoutMs();
try { // 關(guān)鍵語(yǔ)句 retryPolicy.retry(exception); } catch (VolleyError e) { request.addMarker( String.format("%s-timeout-giveup [timeout=%s]", logPrefix, oldTimeout)); throw e; } request.addMarker(String.format("%s-retry [timeout=%s]", logPrefix, oldTimeout)); }
RetryPolicy是一個(gè)接口:
public interface RetryPolicy { public int getCurrentTimeout(); public int getCurrentRetryCount(); public void retry(VolleyError error) throws VolleyError; }
如沒(méi)有特殊指定,request中的RetryPolicy為DefaultRetryPolicy,其retry方法實(shí)現(xiàn)如下:
public void retry(VolleyError error) throws VolleyError { mCurrentRetryCount++; mCurrentTimeoutMs += (mCurrentTimeoutMs * mBackoffMultiplier); if (!hasAttemptRemaining()) { throw error; } }
如果還沒(méi)超出重試次數(shù)上限,那么不會(huì)拋出異常,并返回到performRequest()的while循環(huán)中。接下來(lái)分析一下BaseNetwork的entityToBytes()方法:
private byte[] entityToBytes(HttpEntity entity) throws IOException, ServerError { // 1. 新建PoolingByteArrayOutputStream PoolingByteArrayOutputStream bytes = new PoolingByteArrayOutputStream(mPool, (int) entity.getContentLength()); byte[] buffer = null; try { InputStream in = entity.getContent(); if (in == null) { throw new ServerError(); }
// 2. 在字節(jié)池中取出1024字節(jié)buffer buffer = mPool.getBuf(1024); int count; // 3. 從entity的inputStream中讀出數(shù)據(jù)到buffer while ((count = in.read(buffer)) != -1) { // 將buffer寫(xiě)到PoolingByteArrayOutputStream中 bytes.write(buffer, 0, count); } // 4. 將所有數(shù)據(jù)返回 return bytes.toByteArray(); } finally { try { // Close the InputStream and release the resources by "consuming the content". entity.consumeContent(); } catch (IOException e) { // This can happen if there was an exception above that left the entity in // an invalid state. VolleyLog.v("Error occured when calling consumingContent"); } // 5. 歸還buffer到字節(jié)池 mPool.returnBuf(buffer); bytes.close(); } } 執(zhí)行步驟見(jiàn)代碼注釋。這里不對(duì)ByteArrayPool類和PoolingByteArrayOutputStream展開(kāi)。 HttpStack HttpStack是一個(gè)接口,僅負(fù)責(zé)將request發(fā)送出去: public interface HttpStack { public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders) throws IOException, AuthFailureError; }
從最開(kāi)始的對(duì)Volley類的分析可知,SDK version > 9的情況下使用HurlStack(java.net.HttpURLConnection),否則使用HttpClientStack(org.apache.http.client.HttpClient)。
stack各自實(shí)現(xiàn)了performRequest()方法,在內(nèi)部正式發(fā)起了http請(qǐng)求。具體的用法參考各自的api文檔,這里不詳細(xì)展開(kāi)了。
Request
Request類主要是保存著該次請(qǐng)求的參數(shù)和該次請(qǐng)求當(dāng)前的狀態(tài),本身不含有請(qǐng)求相關(guān)的行為:
public abstract class Request<T> implements Comparable<Request<T>> { ... public interface Method { int DEPRECATED_GET_OR_POST = -1; int GET = 0; int POST = 1; int PUT = 2; int DELETE = 3; int HEAD = 4; int OPTIONS = 5; int TRACE = 6; int PATCH = 7; } ... private final int mMethod; private final String mUrl; private String mRedirectUrl; private String mIdentifier; private final int mDefaultTrafficStatsTag; private Response.ErrorListener mErrorListener; private Integer mSequence; private RequestQueue mRequestQueue; private boolean mShouldCache = true; private boolean mCanceled = false; private boolean mResponseDelivered = false; private RetryPolicy mRetryPolicy; ... }
下面再來(lái)分析一下request.parseNetworkResponse(networkResponse)這個(gè)方法。以StringRequest為例:
@Override protected Response<String> parseNetworkResponse(NetworkResponse response) { String parsed; try { parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers)); } catch (UnsupportedEncodingException e) { parsed = new String(response.data); } return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response)); } 可以看到它只是簡(jiǎn)單地將data轉(zhuǎn)換成string,然后返回一個(gè)success的response。 而JsonObjectRequest的實(shí)現(xiàn)如下: @Override protected Response<JSONObject> parseNetworkResponse(NetworkResponse response) { try { String jsonString = new String(response.data, HttpHeaderParser.parseCharset(response.headers, PROTOCOL_CHARSET)); return Response.success(new JSONObject(jsonString), HttpHeaderParser.parseCacheHeaders(response)); } catch (UnsupportedEncodingException e) { return Response.error(new ParseError(e)); } catch (JSONException je) { return Response.error(new ParseError(je)); } }
它現(xiàn)將data轉(zhuǎn)換成string,然后再生成一個(gè)JSONObject返回。
綜上,Volley的大致框架如下所述:
一個(gè)RequestQueue中包含兩個(gè)內(nèi)部queue,分別是cache queue和network queue。還有一個(gè)cache dispatcher和n個(gè)network dispatcher,它們都繼承成于Thread,分別負(fù)責(zé)執(zhí)行緩存和網(wǎng)絡(luò)請(qǐng)求。還有一個(gè)delivery,負(fù)責(zé)分發(fā)請(qǐng)求結(jié)果。
cache dispatcher在獨(dú)立的線程上運(yùn)行。cache dispatcher循環(huán)等待、取出并執(zhí)行cache queue中的request。把結(jié)果交給delivery。
N個(gè)network dispatcher分別在獨(dú)立的線程上運(yùn)行。network dispatcher循環(huán)等待、取出并執(zhí)行network queue中的request。把結(jié)果交給delivery和添加到cache中。
delivery負(fù)責(zé)在主線程上將結(jié)果傳給相應(yīng)的listener回調(diào)。
以上就是如何Android Volley庫(kù)中HTTP Request部分的源碼分析,小編相信有部分知識(shí)點(diǎn)可能是我們?nèi)粘9ぷ鲿?huì)見(jiàn)到或用到的。希望你能通過(guò)這篇文章學(xué)到更多知識(shí)。更多詳情敬請(qǐng)關(guān)注億速云行業(yè)資訊頻道。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。