Volley Library source code analysis, volley Library source code

Source: Internet
Author: User

Volley Library source code analysis, volley Library source code
Zookeeper Volley uses the thread pool as the basic structure, mainly divided into the main thread, cache thread and network thread.
The main thread and cache thread have only one thread, while the NetworkDispatcher thread can have multiple threads, which can solve parallel problems. For example:

In the lower-left corner, the NetworkDispatcher thread is used. The general steps are as follows: 1. Continuously retrieve requests from the request queue.

request = mQueue.take();
2. Initiate a network request
NetworkResponse networkResponse = mNetwork.performRequest(request);
3. Convert the networkResponse to the expected data type, such as Response <String>, Response <Json>, Response <Bitmap>
Response<?> response = request.parseNetworkResponse(networkResponse);
4. Add the network response to the cache
mCache.put(request.getCacheKey(), response.cacheEntry);

The following is the main code of the NetworkDispatcher thread:
@ Override public void run () {Process. setThreadPriority (Process. THREAD_PRIORITY_BACKGROUND); Request request; while (true) {try {// Take a request from the queue. request = mQueue. take (); // 1. retrieve a network Request from the Request queue. mQueue is the implementation class of BlockingQueue <Request>} catch (InterruptedException e) {// We may have been interrupted because it was time to quit. if (mQuit) {return;} continue;} try {request. addMarker ("net Work-queue-take "); // If the request was canceled already, do not perform the // network request. if (request. isCanceled () {request. finish ("network-discard-canceled"); continue;} // Tag the request (if API> = 14) if (Build. VERSION. SDK_INT> = Build. VERSION_CODES.ICE_CREAM_SANDWICH) {TrafficStats. setThreadStatsTag (request. getTrafficStatsTag ();} // Perform the network request. networkResponse NetworkResponse = mNetwork. required mrequest (request); // 2. initiate a network 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. R Esponse <?> Response = request. parseNetworkResponse (networkResponse); // 3. converts this networkResponse to the expected data type request. addMarker ("network-parse-complete"); // Write to cache if applicable. // TODO: Only update cache metadata instead of entire record for 304 s. if (request. shouldCache () & response. cacheEntry! = Null) {mCache. put (request. getCacheKey (), response. cacheEntry); // 4. add the network response to the cache request. addMarker ("network-cache-written");} // Post the response back. request. markDelivered (); mDelivery. postResponse (request, response);} catch (VolleyError volleyError) {parseAndDeliverNetworkError (request, volleyError);} catch (Exception e) {VolleyLog. e (e, "Unhandled exception % s", e. toString (); mDelivery. postError (request, new VolleyError (e ));}}}

To understand the concurrency Implementation of Volley, you must understand the PriorityBlockingQueue concurrency class. Note that explicit synchronization is not used in the NetworkDispatcher loop (use Lock or synchronize), because the implementation of PriorityBlockingQueue is thread-safe. When explicit wait () and policyall () are used, the coupling between classes can be eliminated because each class only communicates with BlockingQueue. For this knowledge point, refer to Java programming ideas P713. BlockingQueueImplementations are thread-safe. All queuing methods achieve their effects atomically using internal locks or other forms of concurrency control.
Therefore, multiple NetworkDispatcher threads can fetch requests from the request queue PriorityBlockingQueue without thread conflict. Volley supports multi-thread image download.
In fact, the BlockingQueue interface is used to solve the producer-consumer problem.
class Producer implements Runnable {   private final BlockingQueue queue;   Producer(BlockingQueue q) { queue = q; }   public void run() {     try {       while (true) { queue.put(produce()); }     } catch (InterruptedException ex) { ... handle ...}   }   Object produce() { ... } } class Consumer implements Runnable {   private final BlockingQueue queue;   Consumer(BlockingQueue q) { queue = q; }   public void run() {     try {       while (true) { consume(queue.take()); }     } catch (InterruptedException ex) { ... handle ...}   }   void consume(Object x) { ... } } class Setup {   void main() {     BlockingQueue q = new SomeQueueImplementation();     Producer p = new Producer(q);     Consumer c1 = new Consumer(q);     Consumer c2 = new Consumer(q);     new Thread(p).start();     new Thread(c1).start();     new Thread(c2).start();   } }}
In Volley, request is the product, the main thread is the producer, and the NetworkDispatcher thread is the consumer.

It is also noted that the implementation of NetworkDispatcher is actually a policy design mode:
/** The queue of requests to service. */    private final BlockingQueue<Request> mQueue;    /** The network interface for processing requests. */    private final Network mNetwork;    /** The cache to write to. */    private final Cache mCache;    /** For posting responses and errors. */    private final ResponseDelivery mDelivery;    /** Used for telling us to die. */    private volatile boolean mQuit = false;    /**     * Creates a new network dispatcher thread.  You must call {@link #start()}     * in order to begin processing.     *     * @param queue Queue of incoming requests for triage     * @param network Network interface to use for performing requests     * @param cache Cache interface to use for writing responses to cache     * @param delivery Delivery interface to use for posting responses     */    public NetworkDispatcher(BlockingQueue<Request> queue,            Network network, Cache cache,            ResponseDelivery delivery) {        mQueue = queue;        mNetwork = network;        mCache = cache;        mDelivery = delivery;    }
Several parameters of the NetworkDispatcher constructor are interfaces, while the run method uses these policy methods to implement the main process of the algorithm. Some implementations are left for developers, while others are framework implementations. For example, ImageCache is reserved for developers as a Cache Method for level-1 caching, and developers control specific Cache policies. Volley suggests that we use LRUCache as the implementation of L1 caching.
Finally, the NetworkDispatcher array forms the thread pool in the RequestQueue class, which is uniformly started and stopped by RequestQueue:
/**     * Creates the worker pool. Processing will not begin until {@link #start()} is called.     *     * @param cache A Cache to use for persisting responses to disk     * @param network A Network interface for performing HTTP requests     * @param threadPoolSize Number of network dispatcher threads to create     * @param delivery A ResponseDelivery interface for posting responses and errors     */    public RequestQueue(Cache cache, Network network, int threadPoolSize,            ResponseDelivery delivery) {        mCache = cache;        mNetwork = network;        mDispatchers = new NetworkDispatcher[threadPoolSize];        mDelivery = delivery;    }/**     * 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();        }    }



For more information about volley Web requests, see blog: http://www.cnblogs.com/bvin/p/3291611.html



There are several conversion parsing requests in the network request to obtain the response results:

1. The restore mrequest () method of the HttpStack Interface

public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)

2. Network interface's Network mrequest () method

public NetworkResponse performRequest(Request<?> request)

3. parseNetworkResponse () abstract method of the Request class

abstract protected Response<T> parseNetworkResponse(NetworkResponse response);

We can clearly see that the first is the parsing of native Http requests, which is an Apach HttpResponse instance, this result is obtained through the implementation classes HttpClientStack and HurlStack of the above two httpstacks.

The second Parsing is the framework-defined NetworkResponse, which is obtained through the implementation class BasicNetwork of the Network.

The third is the second one. The NetworkResponse is parsed into the desired Response <T>. The Response corresponds to the Request, including the String type, the json type, and the Image type. Then, the parsed result is sent to the main thread through ResponseDelivery.

From the Request to the Response step by step.


Then, let's take a closer look at the second method called "initiate mrequest ()". This method is the second step of the main steps in NetworkDispatcher. The work of real network requests is delegated to mHttpStack for implementation, the HttpStack implementation class is two HttpClientStack and HurlStack executions. The difference between the two classes is that HttpClientStack directly uses the execute () method of HttpClient to execute an Http request, and HurlStack directly uses the URL. openConnection () is used for connection. This method cannot be used in the case of over 2.3, so the two methods are separated.
/*** @ Title javasmrequest executes various Request requests and returns the result in the form of NetworkResponse * @ param Request * @ return NetworkResponse * @ throws VolleyError * Definition: {@ link Network # Your mrequest (Request)} * called: run () of {@ link NetworkDispatcher # run ()} **/@ Override // NetworkDispatcher () call public NetworkResponse response mrequest (Request <?> Request) throws VolleyError {long requestStart = SystemClock. elapsedRealtime (); // start request time while (true) {HttpResponse httpResponse = null; // apache request result byte [] responseContents = null; // request content Map <String, String> responseHeaders = new HashMap <String, String> (); // response result header information try {// Gather headers. map <String, String> headers = new HashMap <String, String> (); // Save the cache data addCacheHeaders (headers, request. getC AcheEntry (); // obtain the cached data first. httpResponse = mHttpStack. initiate mrequest (request, headers); // call the implementation method of mHttpStack to execute the request StatusLine statusLine = httpResponse. getStatusLine (); // get the http status line int statusCode = statusLine. getStatusCode (); // get the status code responseHeaders = convertHeaders (httpResponse. getAllHeaders (); // Handle cache validation. // process cache verification if (statusCode = HttpStatus. SC _NOT_MODIFIED) {// return the cached data return new NetworkRe Response Se (HttpStatus. SC _NOT_MODIFIED, request. getCacheEntry (). data, responseHeaders, true);} // converts HttpEntity to byte [] data responseContents = entityToBytes (httpResponse. getEntity (); // if the request is slow, log it. // if the request is slow, print it out and check whether long requestLifetime = SystemClock. elapsedRealtime ()-requestStart; logSlowRequests (requestLifetime, request, responseContents, statusLine); // print // The connection is normal but no content is returned, throwing an IO exception if (s TatusCode! = HttpStatus. SC _ OK & statusCode! = HttpStatus. SC _NO_CONTENT) {throw new IOException ();} return new NetworkResponse (statusCode, responseContents, responseHeaders, false);} catch (SocketTimeoutException e) {// read timeout, retry attemptRetryOnException ("socket", request, new TimeoutError ();} catch (ConnectTimeoutException e) {// connection timeout, retry attemptRetryOnException ("connection", request, new TimeoutError ();} catch (MalformedURLException e ){// Bad URL throw new RuntimeException ("Bad URL" + request. getUrl (), e);} catch (IOException e) {// IO exception int statusCode = 0; NetworkResponse networkResponse = null; if (httpResponse! = Null) {statusCode = httpResponse. getStatusLine (). getStatusCode ();} else {// if no httpResponse is returned, throw new NoConnectionError (e);} VolleyLog is not connected. e ("Unexpected response code % d for % s", statusCode, request. getUrl (); if (responseContents! = Null) {// The returned data is not null networkResponse = new NetworkResponse (statusCode, responseContents, responseHeaders, false); // create the response body if (statusCode = HttpStatus. SC _UNAUTHORIZED | statusCode = HttpStatus. SC _FORBIDDEN) {// authentication failure exception. Retry attemptRetryOnException ("auth", request, new AuthFailureError (networkResponse);} else {// server exception // TODO: only throw ServerError for 5xx status codes. throw new ServerError (networkResponse); // server exception thrown only when the status code is 5XX} else {// network exception throw new NetworkError (networkResponse );}}}}

A: First, use mHttpStack to execute the request and obtain its response results, and make various judgments based on HttpStatus.

B: Convert the Entity of httpResponse to ByteArray and handle various exceptions.

C: The final process is as follows: Create a RequestQueue Request queue through Volley. When the queue starts to operate, the NetworkDispatcher working thread will be started, while the BasicNetwork's receivmrequest () the NetworkDispatcher method is called in the run () method of the NetworkDispatcher thread, and then a networkResponse is obtained through the initiate mrequest () method of the mHttpStack. In the NetworkDispatcher thread, the networkResponse is converted to the expected data type, for example, Response <String>, Response <Json>, and Response <Bitmap>.


Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

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.