Android: Volley source code parsing

Source: Internet
Author: User
Tags call back

Android: Volley source code parsing
Simple instance

Volley is a network communication framework that encapsulates HttpUrlConnection and HttpClient. It integrates the advantages of AsyncHttpClient and Universal-Image-Loader. It can perform HTTP Communication as easily as AsyncHttpClient, you can also easily load and cache downloaded images like Universal-Image-Loader. Volley has also made significant adjustments in terms of performance. Its design goal isSmall data volume, but frequent network operationsFor network operations that involve a large amount of data, such as downloading files, Volley performs poorly. The following simple example is used to study the source code.

RequestQueue mQueue = Volley.newRequestQueue(MainActivity.this);StringRequest stringRequest = new StringRequest(http://www.baidu.com, new Response.Listener
  
   () {    @Override    public void onResponse(String s) {        tv.setText(s);    }}, new Response.ErrorListener() {    @Override    public void onErrorResponse(VolleyError volleyError) {    }});mQueue.add(stringRequest);
  
Process 1. instantiate a RequestQueue object in the form of a static Factory

RequestQueue mQueue = Volley. newRequestQueue (MainActivity. this );

First, let's take a look at the RequestQueue class:
public class RequestQueue {    private AtomicInteger mSequenceGenerator;    private final Map
  
   > mWaitingRequests;    private final Set
   
     mCurrentRequests;    private final PriorityBlockingQueue
    
      mCacheQueue;    private final PriorityBlockingQueue
     
       mNetworkQueue;    private static final int DEFAULT_NETWORK_THREAD_POOL_SIZE = 4;    private final Cache mCache;    private final Network mNetwork;    private final ResponseDelivery mDelivery;    private NetworkDispatcher[] mDispatchers;    private CacheDispatcher mCacheDispatcher;    public RequestQueue(Cache cache, Network network, int threadPoolSize, ResponseDelivery delivery) {        this.mSequenceGenerator = new AtomicInteger();        this.mWaitingRequests = new HashMap();        this.mCurrentRequests = new HashSet();        this.mCacheQueue = new PriorityBlockingQueue();        this.mNetworkQueue = new PriorityBlockingQueue();        this.mCache = cache;        this.mNetwork = network;        this.mDispatchers = new NetworkDispatcher[threadPoolSize];        this.mDelivery = delivery;    }    public RequestQueue(Cache cache, Network network, int threadPoolSize) {        this(cache, network, threadPoolSize, new ExecutorDelivery(new Handler(Looper.getMainLooper())));    }    public RequestQueue(Cache cache, Network network) {        this(cache, network, 4);    }    ...}
     
    
   
  

From the constructor, we can see that mWaitingRequests, mCurrentRequests, mCacheQueue, and mNetworkQueue are instantiated in the form of combination, and the latter two are blocking queues, while mCache and mNetwork are injected in the form of aggregation; mdelivernew ExecutorDelivery(new Handler(Looper.getMainLooper())))Instantiation.

NewRequestQueue method:
public static RequestQueue newRequestQueue(Context context) {        return newRequestQueue(context, (HttpStack)null);    }
 public static RequestQueue newRequestQueue(Context context, HttpStack stack) {        File cacheDir = new File(context.getCacheDir(), volley);        String userAgent = volley/0;        try {            String network = context.getPackageName();            PackageInfo queue = context.getPackageManager().getPackageInfo(network, 0);            userAgent = network + / + queue.versionCode;        } catch (NameNotFoundException var6) {            ;        }        if(stack == null) {            if(VERSION.SDK_INT >= 9) {                stack = new HurlStack();            } else {                stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));            }        }        BasicNetwork network1 = new BasicNetwork((HttpStack)stack);        RequestQueue queue1 = new RequestQueue(new DiskBasedCache(cacheDir), network1);        queue1.start();        return queue1;    }

According to the RequestQueue class, the instantiated RequestQueue object is injectednew DiskBasedCache(cacheDir)Andnetwork1By default, the cache mode is disk cache. NetWork objects use different Http Communication Methods Based on the system version.

Queue. start () method
public void start() {        this.stop();        this.mCacheDispatcher = new CacheDispatcher(this.mCacheQueue, this.mNetworkQueue, this.mCache, this.mDelivery);        this.mCacheDispatcher.start();        for(int i = 0; i < this.mDispatchers.length; ++i) {            NetworkDispatcher networkDispatcher = new NetworkDispatcher(this.mNetworkQueue, this.mNetwork, this.mCache, this.mDelivery);            this.mDispatchers[i] = networkDispatcher;            networkDispatcher.start();        }    }

Both CacheDispatcher and NetworkDispatcher inherit the Thread class. Therefore, this method generates a cache distribution Thread and four network threads.

The CacheDispatcher class inherits the Thread class, And all parameters are injected in an aggregate form. Check the key run () method. Because the code is long, it is not pasted here. Several important methods are analyzed in segmentation.
while(true){    ...    Request e = (Request)this.mCacheQueue.take();    ...}

The first task is an endless loop. Since mCacheQueue is a blocking queue, the Request will be continuously read from the blocking queue.

 Entry entry = this.mCache.get(e.getCacheKey());                                    if(entry == null) {                                        e.addMarker(cache-miss);                                        this.mNetworkQueue.put(e);                                    } else if(entry.isExpired()) {                                        e.addMarker(cache-hit-expired);                                        e.setCacheEntry(entry);                                        this.mNetworkQueue.put(e);                                    } else {                                        e.addMarker(cache-hit);                                        Response response = e.parseNetworkResponse(new NetworkResponse(entry.data, entry.responseHeaders));                                        ...                                        }

Determine whether the request is cached,If no or the cache expires, put the request in the network queue.. Otherwise, find the cache and perform the following operations.

Response response = e.parseNetworkResponse(new NetworkResponse(entry.data, entry.responseHeaders));

ParseNetworkResponse is the abstract method of the Request class. Let's go to StringRequest and see:

protected Response
  
    parseNetworkResponse(NetworkResponse response) {        String parsed;        try {            parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers));        } catch (UnsupportedEncodingException var4) {            parsed = new String(response.data);        }        return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response));    }
  

It can be seen that the downloaded data is parsed and then returned.

this.mDelivery.postResponse(e, response);

In this step, mDelivery injects CacheDispatcher into the RequestQueue instance. The specific instantiated object is new ExecutorDelivery (new Handler (Looper. getmainlocher ())). Take a look at the ExecutorDelivery class and find the postResponse method.

    public void postResponse(Request
   request, Response
   response) {        this.postResponse(request, response, (Runnable)null);    }    public void postResponse(Request
   request, Response
   response, Runnable runnable) {    ...        this.mResponsePoster.execute(new ExecutorDelivery.ResponseDeliveryRunnable(request, response, runnable));    }

Continue to look down

private class ResponseDeliveryRunnable implements Runnable {    ...    run(){        ...        if(this.mResponse.isSuccess()) {                    this.mRequest.deliverResponse(this.mResponse.result);                }         ...    }    ...}

The deliverResponse method is also an abstract method of the Request class. Let's look at it in StringRequest.

    protected void deliverResponse(String response) {        this.mListener.onResponse(response);    }

Just one callback

The NetworkDispatcher class also inherits the Thread class, and its analysis process is similar to that of CacheDispatcher. The important steps are as follows:

1. Read requests from the network blocking queue, request = (Request) this. mQueue. take ();
2. Network download, NetworkResponse e = this. mNetwork. Fetch mrequest (request); (if it is CacheDispatcher, this step is the cache judgment)
3. process the downloaded data, Response response = request. parseNetworkResponse (e );
3. Call back the processed data. this. mDelivery. postResponse (e, response ).

2. instantiate a Request object

StringRequest stringRequest = new StringRequest (url, listener, errorListener );

public class StringRequest extends Request
  
    {    private final Listener
   
     mListener;    public StringRequest(int method, String url, Listener
    
      listener, ErrorListener errorListener) {        super(method, url, errorListener);        this.mListener = listener;    }    public StringRequest(String url, Listener
     
       listener, ErrorListener errorListener) {        this(0, url, listener, errorListener);    }    protected void deliverResponse(String response) {        this.mListener.onResponse(response);    }    protected Response
      
        parseNetworkResponse(NetworkResponse response) { String parsed; try { parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers)); } catch (UnsupportedEncodingException var4) { parsed = new String(response.data); } return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response)); }}
      
     
    
   
  

As you can see from the first analysis step, this Request mainly performs two operations, that is, rewriting two methods.

protected abstract Response parseNetworkResponse(NetworkResponse var1); Parse the downloaded data; protected abstract void deliverResponse(T var1);The method used to call back the data.

Therefore, the constructor only needs the callback operation method.

3. Call the queue. add () method.
 if(!request.shouldCache()) {            this.mNetworkQueue.add(request);            return request;        } 

If no cache is required, the Request is directly added to the network queue. The Request has an important Boolean field mShouldCache, which is used by default to determine whether to cache the disk.

this.mCacheQueue.add(request);

Otherwise, it will be added to the cache queue. This method also performs some anti-repeated operations on the current queue and the waiting queue.

Summary

Framework section:
1. instantiate a RequestQueue object, enable a cache thread and four default network threads, and the thread constantly reads requests from the cache blocking queue and network blocking queue;
2. If the request read by the cache thread from the cache queue has been cached, the data callback operation method will be parsed; otherwise, the request will be added to the network queue;
3. If the request read by the cache thread from the cache queue has not been cached, it is added to the network queue.
4. The network thread constantly reads requests from the network blocking queue. After reading the request, the encapsulated HttpStack object is used for network download processing and callback for data processing after download, method of Data callback after processing.

Customer:
1. instantiate a request object. In the request object, rewrite the method for processing the downloaded data from the network and the method for operating the processed data.
2. Add the request object to the Request queue. If the request needs to be cached, the request is added to the allocated cache queue. If the request does not need to be cached, the request is added to the network queue.

I have read a question before, saying what is the difference between the framework and the library. The speaker replied: The Framework calls your code, and the library calls your code. The excellent framework is so powerful in scalability, although far from that ability, it is also an eye-opener!

 

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.