Volley簡單學習使用五—— 源碼分析三,volley源碼分析
一、Volley工作流程圖:
二、Network 在NetworkDispatcher中需要處理的網路請求,由下面進行處理:
NetworkResponse networkResponse = mNetwork.performRequest(request);
看一下mNetwork的定義:(定義在NetworkDispatcher中)
/** The network interface for processing requests. */ private final Network mNetwork;
NetworkDispatcher.mNetwork初始化發生在RequestQueue.start()中:
NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork, mCache, mDelivery);
而RequestQueue.mNetwork是在其建構函式中傳入的:
public RequestQueue(Cache cache, Network network, int threadPoolSize, ResponseDelivery delivery) { mCache = cache; mNetwork = network; mDispatchers = new NetworkDispatcher[threadPoolSize]; mDelivery = delivery; }由前面分析知RequestQueue的構建是在Volley.newRequestQueue中實現的:
//建立以stack為參數的Network對象 Network network = new BasicNetwork(stack); //建立RequestQueue對象 RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir), network); queue.start();//繼續向下分析的入口
可以看出mNetwork其實是BasicNetwork對象。 則NetworkResponse中mNetwork實際上調用的是BasicNetwork.performRequest(),這是一個專門用來處理網路請求的函數,其作用為調用
HttpStack處理請求,並將結果轉換為可被
ResponseDelivery處理的
NetworkResponse。看一下其源碼:
@Override public NetworkResponse performRequest(Request<?> request) throws VolleyError { long requestStart = SystemClock.elapsedRealtime(); while (true) { HttpResponse httpResponse = null; byte[] responseContents = null; Map<String, String> responseHeaders = new HashMap<String, String>(); try { /** 忽略網路處理的細節*/ // Gather headers. Map<String, String> headers = new HashMap<String, String>(); addCacheHeaders(headers, request.getCacheEntry()); /**執行網路請求 * 這裡調用了HttpStack.performRequest,並得到一個HttpResponse返回結果*/ httpResponse = mHttpStack.performRequest(request, headers); StatusLine statusLine = httpResponse.getStatusLine(); int statusCode = statusLine.getStatusCode(); responseHeaders = convertHeaders(httpResponse.getAllHeaders()); /**新鮮度驗證: * 304 Not Modified:用戶端有緩衝的檔案並發出了一個條件性的請求 * (一般是提供If-Modified-Since頭表示客戶只想比指定日期更新的文檔)。 * 伺服器告訴客戶,原來緩衝的文檔還可以繼續使用。*/ if (statusCode == HttpStatus.SC_NOT_MODIFIED) { /** 解析成NetworkResponse,返回*/ return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED, request.getCacheEntry().data, responseHeaders, true); } // 判斷responses是否有實體資訊,一些響應如204,並不包含content,所以需要驗證 if (httpResponse.getEntity() != null) { //實體資訊轉化成byte[] responseContents = entityToBytes(httpResponse.getEntity()); } else { // 無實體資訊情況 responseContents = new byte[0]; } // 逾時情況處理. 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); } 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) { ... } } }
總結一下Network.performRequest所做的工作:
1、由傳入的HttpStack對象執行網路請求:mHttpStack.performRequest()
2、解析響應結果,將HttpResponse解析成NetworkResponse;
3、對返回結果進行新鮮度驗證(304)
4、將response的實體資訊轉化為byte數組
5、逾時情況處理,如果發生逾時,認證失敗等錯誤,進行重試操作(attemptRetryOnException),直到成功、拋出異常(不滿足重試策略等)結束。
attemptRetryOnException()是根據重試策略進行請求重試操作:
/** * Attempts to prepare the request for a retry. If there are no more attempts remaining in the * request's retry policy, a timeout exception is thrown. */ private static void attemptRetryOnException(String logPrefix, Request<?> request, VolleyError exception) throws VolleyError { RetryPolicy retryPolicy = request.getRetryPolicy(); int oldTimeout = request.getTimeoutMs(); try { 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)); }
三、HttpClientStack、HurlStack 據上面源碼知,網路請求處理的邏輯實際上是交由傳進來的參數HttpStack進行處理。前面已經分析過,Android2.3之前使用 HttpClientStack,之後使用HurlStack;
1、先看兩者的父類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 發起請求之前,添加額外的請求 Headers {@link Request#getHeaders()} */ public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders) throws IOException, AuthFailureError; }
2、HttpClientStack(使用HttpClient來實現)
@Override public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders) throws IOException, AuthFailureError { HttpUriRequest httpRequest = createHttpRequest(request, additionalHeaders);//見附一 addHeaders(httpRequest, additionalHeaders); addHeaders(httpRequest, request.getHeaders()); onPrepareRequest(httpRequest);// Nothing.空函數,用於重寫;該函數在request被excute之前被調用 //一些網路設定 HttpParams httpParams = httpRequest.getParams(); int timeoutMs = request.getTimeoutMs(); // TODO: Reevaluate this connection timeout based on more wide-scale // data collection and possibly different for wifi vs. 3G. HttpConnectionParams.setConnectionTimeout(httpParams, 5000); HttpConnectionParams.setSoTimeout(httpParams, timeoutMs); return mClient.execute(httpRequest); }附一:createHttpRequest函數:
/** * 根據傳進來的request來構造合適的HttpUriRequest */ static HttpUriRequest createHttpRequest(Request<?> request, Map<String, String> additionalHeaders) throws AuthFailureError { switch (request.getMethod()) { case Method.DEPRECATED_GET_OR_POST: { // This is the deprecated way that needs to be handled for backwards compatibility. // If the request's post body is null, then the assumption is that the request is // GET. Otherwise, it is assumed that the request is a POST. byte[] postBody = request.getPostBody(); if (postBody != null) { HttpPost postRequest = new HttpPost(request.getUrl()); postRequest.addHeader(HEADER_CONTENT_TYPE, request.getPostBodyContentType()); HttpEntity entity; entity = new ByteArrayEntity(postBody); postRequest.setEntity(entity); return postRequest; } else { return new HttpGet(request.getUrl()); } } /***********一般較多使用的是POST與GET,其等同於HttpClient的一般使用流程***************/ case Method.GET: return new HttpGet(request.getUrl()); case Method.DELETE: return new HttpDelete(request.getUrl()); case Method.POST: { HttpPost postRequest = new HttpPost(request.getUrl()); //這裡就看到了前面實現Request時,重寫getBodyContentType()函數的意義 postRequest.addHeader(HEADER_CONTENT_TYPE, request.getBodyContentType()); setEntityIfNonEmptyBody(postRequest, request); return postRequest; } case Method.PUT: { HttpPut putRequest = new HttpPut(request.getUrl()); putRequest.addHeader(HEADER_CONTENT_TYPE, request.getBodyContentType()); setEntityIfNonEmptyBody(putRequest, request); return putRequest; } default: throw new IllegalStateException("Unknown request method."); } }
3、HurlStack(由HttpURLConnection來實現)
@Override 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); //UrlRewriter見附一 if (mUrlRewriter != null) { String rewritten = mUrlRewriter.rewriteUrl(url); if (rewritten == null) { thrownew IOException("URL blocked by rewriter: " + url); } url = rewritten; } /**************HttpURLConnection的一般使用流程*******************/ URL parsedUrl = new URL(url); HttpURLConnection connection = openConnection(parsedUrl, request); 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. thrownew IOException("Could not retrieve response code from HttpUrlConnection."); } StatusLine responseStatus = new BasicStatusLine(protocolVersion, connection.getResponseCode(), connection.getResponseMessage()); BasicHttpResponse response = new BasicHttpResponse(responseStatus); 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; }附一:UrlRewriter
/** 對URLs在使用前進行重寫轉換*/ public interface UrlRewriter { /** * Returns a URL to use instead of the provided one, or null to indicate * this URL should not be used at all. */ public String rewriteUrl(String originalUrl); }參數mUrlRewriter通過HttpStack的建構函式傳入進來,故可以自行進行定義:
public HurlStack(UrlRewriter urlRewriter, SSLSocketFactory sslSocketFactory) { mUrlRewriter = urlRewriter; mSslSocketFactory = sslSocketFactory; }
四、NetworkResponse 回到起點NetworkDispatcher(Thread)中的run()函數,其中:
NetworkResponse networkResponse = mNetwork.performRequest(request);
下面繼續看NetworkResponse的源碼:NetworkResponse類很簡單,僅是用以在多個類中傳遞資料,其成員變數:1)成員變數
int statusCode Http 響應狀態代碼
byte[] data Body 資料
Map<String, String> headers 響應 Headers
boolean notModified 表示是否為 304 響應
long networkTimeMs 請求耗時
2)其主體只為幾個建構函式:
public NetworkResponse(int statusCode, byte[] data, Map<String, String> headers, boolean notModified) { this.statusCode = statusCode; this.data = data; this.headers = headers; this.notModified = notModified; } public NetworkResponse(byte[] data) { this(HttpStatus.SC_OK, data, Collections.<String, String>emptyMap(), false); } public NetworkResponse(byte[] data, Map<String, String> headers) { this(HttpStatus.SC_OK, data, headers, false); }3)回顧一下前面分析的設計NetworkResponse的類之間資料的傳遞關係:
這裡的主體是根據NetworkDispatcher.run()函數進行分析的0、函數中調用Network.performRequest(); NetworkResponse networkResponse = mNetwork.performRequest(request); 而Network.performRequest()是基於HttpStack實現的;1、HttpClientStack與HurlStack(分別基於HttpClient與HttpURLConnection實現)中的public HttpResponse performRequest()函數返回HttpResponse ;2、Network(實際為BasicNetwork)中performRequest()方法,使用1中的兩個HttpStack類,擷取到其返回值HttpResponse,然後將其解析成為NetworkResponse;3、Request中 abstract protected Response<T> parseNetworkResponse(NetworkResponse response); 將NetworkResponse解析成Response; 而該函數的調用是在NetworkDispatcher中的run()函數中調用的; 4、在NetworkDispatcher.run()的最後一步: mDelivery.postResponse(request, response); 將response傳遞給了ResponseDelivery後面繼續看Delivery的邏輯;