Volley源码解析

来源:互联网 发布:python android 逆向 编辑:程序博客网 时间:2024/05/18 02:55

一、简介

Volley是谷歌官方提供的Android应用程序网络请求框架。
1、入口
RequestQueue类中的add方法。

/**     * Adds a Request to the dispatch queue.     * @param request The request to service     * @return The passed-in request     */    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");        // 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;        }    }

判断该Request是否需要缓存,需要则通过Map<String,LinkList<Request>> mWaitingRequests(Key是该请求的唯一标签,value是包含了正在等待的相同请求的链表) 判断是否已经有相同的请求尚未被处理,如果有就将该Request添加到mWaitingRequests中对应的链表中,没有就将添加到缓存队列CacheQueue中;如果Request不需要缓存,直接将添加到网络队列mNetworkQueue中;

 /**     * Starts the dispatchers in this queue.     */    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();        }    }

RequestQueue中的start方法中创建了一个缓存线程CacheDispatcher 和若干个网络线程NetworkDispatcher(由RequestQueue构造函数的threadPoolSize参数控制); 这两个线程不断的从对应的队列中取Request,先来看CacheDispatcher的run方法:

@Override    public void run() {        while (true) {            try {                // Get a request from the cache triage queue, blocking until                // at least one is available.                final Request<?> request = mCacheQueue.take();                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;                }

在run方法中无限循环的从CacheQueue中取Request,并且会在多个地方调用request.isCanceled()方法判断请求是否被取消;如果没有被取消:

 // Attempt to retrieve this item from cache.                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;                }                // If it is completely expired, just send it to the network.                if (entry.isExpired()) {                    request.addMarker("cache-hit-expired");                    request.setCacheEntry(entry);                    mNetworkQueue.put(request);                    continue;                }                // We have a cache hit; parse its data for delivery back to the request.                request.addMarker("cache-hit");                Response<?> response = request.parseNetworkResponse(                        new NetworkResponse(entry.data, entry.responseHeaders));                request.addMarker("cache-hit-parsed");

根据key在Cache中取出缓存数据Cache.Entry如果取不到或者缓存已过期,则将Request加到NetworkQueue中重新从网络获取数据。如果缓存可以使用,则调用Reqeust.parseNetworkResponse(NetworkResponse response)方法将NetwrokResponse解析成Response<T>;

 if (!entry.refreshNeeded()) {                    // Completely unexpired cache hit. Just deliver the response.                    mDelivery.postResponse(request, response);                } else {                    // 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.                            }                        }                    });                }

拿到Response<T>后,通过ExecutorDelivery将结果返回,再根据entry.refreshNeeded()判断该缓存Request是否需要请求服务器以便下次请求时返回;

Volley通过 ExecutorDelivery将请求结果返回,Executor的代码非常简单,它的作用是提供一种将任务提交与每个任务将如何运行的机制(包括线程使用的细节、调度等)分离开来的方法,在Volley中是这样做的:

 mResponsePoster = new Executor() {            @Override            public void execute(Runnable command) {                handler.post(command);            }        };

创建一个Executor对象,并且重写execute方法,就是说如果调用mResponsePoster .execute方法提交一个任务,那么就会交给Handler处理,如果没有Executor,每次有任务要提交,都要执行handler.post(Runnable command);非常的不灵活,耦合性太高。

 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()) {                mRequest.deliverResponse(mResponse.result);            } 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();            }       }

继续回到ExecutorDelivery,通过Request中的deliverResponse方法将结果返回。

接下来就是重头戏了:

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);            } 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);            }        }

这是NetworkDispatcher中的run方法,也是无限循环地从NetworkQueue中取Request;

// Perform the network request.NetworkResponse networkResponse = mNetwork.performRequest(request);

调用Network中的performRequest方法向服务器发起请求;

@Override    public NetworkResponse performRequest(Request<?> request) throws VolleyError {        long requestStart = SystemClock.elapsedRealtime();        while (true) {            HttpResponse httpResponse = null;            byte[] responseContents = null;            Map<String, String> responseHeaders = Collections.emptyMap();            try {                // Gather headers.                Map<String, String> headers = new HashMap<String, String>();                addCacheHeaders(headers, request.getCacheEntry());                httpResponse = mHttpStack.performRequest(request, headers);                StatusLine statusLine = httpResponse.getStatusLine();                int statusCode = statusLine.getStatusCode();                responseHeaders = convertHeaders(httpResponse.getAllHeaders());                // Handle cache validation.                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);                    }                    // A HTTP 304 response does not have all header fields. We                    // have to use the header fields from the cache entry plus                    // the new ones from the response.                    // http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.5                    entry.responseHeaders.putAll(responseHeaders);                    return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED, entry.data,                            entry.responseHeaders, true,                            SystemClock.elapsedRealtime() - requestStart);                }                // Some responses such as 204s do not have content.  We must check.                if (httpResponse.getEntity() != null) {                  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);

这里的while(true)循环是实现请求重试机制的关键,我们待会儿再讲。真正与服务器的交互,也就是Http请求,是在HttpStack中实现的,在sdk小于9的版本中是用HttpClient实现的,sdk >= 9的版本直接用HttpUrlConnection实现的,我们来看下HurlStack:

@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);        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);        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);        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;    }

根据Request中的url,header,body用HttpUrlConnection与服务器交互,得到服务器返回的HttpResponse后再返回给Network,在Network中将statusCode,header和contents构建出NetworkResponse返回NetworkDispatcher中,调用Request的parseNetworkResponse方法根据用户的要求将NetworkResponse中的contents解析成用户能直接用的Response<T>例如JSONObjectRequest:

 @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));        }    }

response.data就是服务器返回的contents,将其转成jsonString,返回Response<JSONObject>
NetworkDispatcher拿到Response<T>后,先判断该Request是否需要缓存,需要则用Cache类缓存好数据,最后用ExecutorDelivery返回给Request中,具体操作和CacheDispatcher一致。
接下来讲重试机制:
Network在与服务器交互的过程中如果遇到了异常就会调用attemptRetryOnException(String logPrefix, Request

/**     * Returns true if this policy has attempts remaining, false otherwise.     */    protected boolean hasAttemptRemaining() {        return mCurrentRetryCount <= mMaxNumRetries;    } /**     * Prepares for the next retry by applying a backoff to the timeout.     * @param error The error code of the last attempt.     */    @Override    public void retry(VolleyError error) throws VolleyError {        mCurrentRetryCount++;        mCurrentTimeoutMs += (mCurrentTimeoutMs * mBackoffMultiplier);        if (!hasAttemptRemaining()) {            throw error;        }    }

hasAttemptRemaining()方法就是判断重试的次数有没有超过限制,如果没有超过就继续在Network的while(true)循环中与服务器交互,如果超过了,就抛出exception,由于Network中并没有catch VolleyError,所以会跳出Network的while(true)循环,由NetworkDispatcher处理。

1 0