Volley簡單學習使用五—— 源碼分析三,volley源碼分析

來源:互聯網
上載者:User

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的邏輯;

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.