Volley in the quick Android Development Series

Source: Internet
Author: User

Volley is a network request Library launched by Google and has been put into the Android source code. The address is here. Let's take a look at the usage method first.

RequestQueue mRequestQueue = Volley.newRequestQueue(context);JsonObjectRequest req = new JsonObjectRequest(URL, null,       new Response.Listener<JSONObject>() {           @Override           public void onResponse(JSONObject response) {               try {                   VolleyLog.v("Response:%n %s", response.toString(4));               } catch (JSONException e) {                   e.printStackTrace();               }           }       }, new Response.ErrorListener() {           @Override           public void onErrorResponse(VolleyError error) {               VolleyLog.e("Error: ", error.getMessage());           }       });mRequestQueue.add(req);

The detailed usage will not be mentioned. There are a lot of online resources. You can refer to this. Here we will only introduce Volley's working methods, starting from the above example.

The core of Volley we have come into contact with is two. We can see its purpose from its name.

  • RequestQueue
  • Request

We have seen that RequestQueue is obtained through the Volley method newRequestQueue. The only function of the Volley class is to obtain the instance of RequestQueue, and we can use new RequestQueue, I don't know why I didn't merge these two classes.

/** * Creates a default instance of the worker pool and calls {@link RequestQueue#start()} on it. * * @param context A {@link Context} to use for creating the cache dir. * @param stack An {@link HttpStack} to use for the network, or null for default. * @return A started {@link RequestQueue} instance. */public static RequestQueue newRequestQueue(Context context, HttpStack stack) {    File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR);    String userAgent = "volley/0";    try {        String packageName = context.getPackageName();        PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0);        userAgent = packageName + "/" + info.versionCode;    } catch (NameNotFoundException e) {    }    if (stack == null) {        if (Build.VERSION.SDK_INT >= 9) {            stack = new HurlStack();        } else {            // Prior to Gingerbread, HttpUrlConnection was unreliable.            // See: http://android-developers.blogspot.com/2011/09/androids-http-clients.html            stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));        }    }    Network network = new BasicNetwork(stack);    RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir), network);    queue.start();    return queue;}/** * Creates a default instance of the worker pool and calls {@link RequestQueue#start()} on it. * * @param context A {@link Context} to use for creating the cache dir. * @return A started {@link RequestQueue} instance. */public static RequestQueue newRequestQueue(Context context) {    return newRequestQueue(context, null);}

There are several important concepts in newRequestQueue. First, we can see that newRequestQueue has an overload method to receive an HttpStack instance. HttpStack has only one method: descrimrequest, which is used to execute network requests and return HttpResponse, if this parameter is not set, you can choose the parameter based on the API Level:

  • When the API is greater than or equal to 9, that is, 2.3 or later, the system uses HurlStack.
  • 2.3 previous systems used HttpClientStack

The names of these two classes tell us the difference: HurlStack uses HttpURLConnection to execute network requests internally, and HttpClientStack uses HttpClient to execute network requests internally. Why, you can bring your own ladder to read this article.


Network is the Network Request interface. There is only one implementation class BasicNetwork, and there is only one method for sending mrequest. when the Request is executed, NetworkResponse is returned.

Both the Network and HttpStack interfaces have only one method. The differences between the methods can be seen from the method names. when mrequest receives the Request parameter, the system returns om. android. volley. networkResponse, HttpStack. org. apache. http. httpResponse, with a lower level, so it should be a Network. httpStack. execute the actual request and set HttpStack. org. apache. http. httpResponse is encapsulated into com. android. volley. networkResponse returns.


In Volley, The DiskBasedCache subclass of the Cache interface is used for caching. This is a File Cache. The Cache interface has an initialize method to initialize the Cache. This method may perform time-consuming operations, it needs to be executed in the background thread. You can see DiskBasedCache. When it writes the cache to a file, it writes some Header information in the file Header, in initialize, the Header information is read into the memory.

In the Request class, there is a method called parseNetworkResponse. The subclass of the Request will overwrite the result of this method to parse the network Request. In this method, it will call

return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response));

Return Response <T> and use HttpHeaderParse. parseCacheHeaders parses the Cache. entity, that is, the Cache object is generated. In parseaCheHeaders, the system determines whether to Cache the object based on the Expires, Cache-Control, and other information in the Header in the network request results. If not, the system returns null without caching.

After the request is cached, data can be obtained without a network.

Cache also has a subclass called NoCache. The get method returns Null, and other methods are empty. Therefore, NoCache indicates that no Cache is required.



public RequestQueue(Cache cache, Network network, int threadPoolSize) {
this(cache, network, threadPoolSize,            new ExecutorDelivery(new Handler(Looper.getMainLooper())));}/** * 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 */public RequestQueue(Cache cache, Network network) {    this(cache, network, DEFAULT_NETWORK_THREAD_POOL_SIZE);}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 is a request queue that distributes requests and retrieves Cache or read networks. Therefore, a Cache object and a Network object are required in the constructor, and a ResponseDelivery object is used to distribute results.

After creating a RequestQueue, you need to call its start method. In start, a new CacheDispatcher and several NetworkDispatcher are created to process cache and network requests respectively.

Add a request using the add method of RequestQueue:

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

The add method has the following steps:

These are the tasks of RequestQueue. add. As you can see, it does not execute any actual request operations, including determining the cache and request network. The following two classes will be called for direct operations.

mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery);

In RequestQueue. in the add method, if the cache is used, the Request is directly put into the cache queue mCacheQueue. The location where mCacheQueue is used is CacheDispatcher, the CacheDispatcher constructor contains the cache queue mCacheQueue, network queue mNetworkQueue, cache object mCache, and result dispatcher mDelivery.

CacheDispatcher inherits from the Thread. After being started, it executes its run method. The code is not pasted, mainly to complete the following tasks:

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.        }    }});
NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork, mCache, mDelivery);

NetworkDispatcher works in the same way as CacheDispatcher. It inherits from the Thread. After being started, it constantly retrieves requests from mNetworkQueue and then requests the Network through the Network interface.

After obtaining the request result, if the server returns 304 (the result has not changed since the last request) and the result has been distributed through the cache (that is, this is the Refresh after the cache is read ), otherwise, call the Request parseNetworkResponse to parse the Request result. If you need to cache the Request and dispatch the result


The interface for distributing request results. A subclass of ExecutorDelivery is used to execute the actual operation. To construct an ExecutorDelivery object, a Handler object is required. When a result is distributed to ExecutorDelivery, a post message is sent to the Handler.


Request indicates a Request with four priorities: LOW, NORMAL, HIGH, and IMMEDIATE. The following methods are used:

  • GetHeaders: Get the Http Header list of the request
  • GetBodyContentType request type, such as application/x-www-form-urlencoded; charset = UTF-8
  • Content of the POST or PUT request to be sent by getBody
  • GetParams: get the parameters of the POST or PUT request. If you override getBody, this will not be used.
  • ParseNetworkResponse parses the request result to the desired type and NetworkResponse to Response <T>. The data member in NetworkResponse indicates that the network request result is byte []
  • The deliverResponse subclass must be implemented to distribute the results to Listener.

StringRequest converts the result to String and Deliver to Response. Listener

@Overrideprotected void deliverResponse(String response) {    mListener.onResponse(response);}@Overrideprotected Response<String> parseNetworkResponse(NetworkResponse response) {    String parsed;    try {        parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers));    } catch (UnsupportedEncodingException e) {        parsed = new String(response.data);    }    return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response));}

JsonRequest <T>

You can send a JSONObject parameter at the same time when sending a request, overwriting the getBody

@Overridepublic byte[] getBody() {    try {        return mRequestBody == null ? null : mRequestBody.getBytes(PROTOCOL_CHARSET);    } catch (UnsupportedEncodingException uee) {        VolleyLog.wtf("Unsupported Encoding while trying to get the bytes of %s using %s",                mRequestBody, PROTOCOL_CHARSET);        return null;    }}

MRequestBody is a String passed in the constructor, which is generally JSONObject. toString ().


Inherited from JSONRequest <T>, parses the request result into a JSONObject

public JsonObjectRequest(int method, String url, JSONObject jsonRequest,        Listener<JSONObject> listener, ErrorListener errorListener) {    super(method, url, (jsonRequest == null) ? null : jsonRequest.toString(), listener,                errorListener);}@Overrideprotected Response<JSONObject> rkResponse(NetworkResponse response) {    try {        String jsonString =            new String(response.data, HttpHeaderParser.parseCharset(response.headers));        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));    }}


Like JsonObjectRequest, It inherits from JSONRequest <T>, but parses the result into JSONArray.


Hack requests are used to clear the cache and set to the highest priority IMMEDIATE. when the Request is executed, Request. isCanceled is called to determine whether the Request has been canceled. The cache is cleared here.

@Overridepublic boolean isCanceled() {    // This is a little bit of a hack, but hey, why not.    mCache.clear();    if (mCallback != null) {        Handler handler = new Handler(Looper.getMainLooper());        handler.postAtFrontOfQueue(mCallback);    }    return true;}


RequestQueue also provides the method to cancel the request. Use its cancelAll method.

/** * A simple predicate or filter interface for Requests, for use by * {@link RequestQueue#cancelAll(RequestFilter)}. */public interface RequestFilter {    public boolean apply(Request<?> request);}/** * Cancels all requests in this queue for which the given filter applies. * @param filter The filtering function to use */public void cancelAll(RequestFilter filter) {    synchronized (mCurrentRequests) {        for (Request<?> request : mCurrentRequests) {            if (filter.apply(request)) {                request.cancel();            }        }    }}/** * Cancels all requests in this queue with the given tag. Tag must be non-null * and equality is by identity. */public void cancelAll(final Object tag) {    if (tag == null) {        throw new IllegalArgumentException("Cannot cancelAll with a null tag");    }    cancelAll(new RequestFilter() {        @Override        public boolean apply(Request<?> request) {            return request.getTag() == tag;        }    });}

By setting a Tag for each request, cancelAll (final Object tag) can be used to cancel the request for the corresponding Tag, or you can directly use RequestFilter

Image loading

Using ImageRequest, ImageLoader, NetworkImageView, and other classes, Volley can also be used to load images. By locking, Volley can parse only one image at the same time, instead of loading only one image, network requests are still the same as normal requests. The returned byte array is used for parsing byte []-> Bitmap. Because the request result is byte [], the large image should easily cause memory overflow, it does not support local images, so it is skipped.


Volley's expansion should be relatively easy. There are already various versions of network extensions, such as Cache and Request interfaces, which are easy to implement, for example, GsonRequest is implemented to use Gson to parse the returned json results:

protected Response<T> parseNetworkResponse(NetworkResponse response) {    try {        String json = new String(                response.data, HttpHeaderParser.parseCharset(response.headers));        return Response.success(                gson.fromJson(json, clazz), HttpHeaderParser.parseCacheHeaders(response));    } catch (UnsupportedEncodingException e) {        return Response.error(new ParseError(e));    } catch (JsonSyntaxException e) {        return Response.error(new ParseError(e));    }}

 Volley is designed for small network requestsSo it is not suitable for uploading and downloading large files. Although there are corresponding extensions on the Internet, there is no native file upload.

Although Volley has NetImageView, ImageLoader, and so on related to image loading, I am not willing to use it myself. It should be easy to use OOM to return and parse the request results as byte, besides, there are other excellent image loading libraries, such as UniversalImageLoader.

Although Volley is fast and easy to expand on the internet, it also provides comparative data, but it always needs to be manually expanded, and it does not show any significant advantages, unlike Android-Async-HttpHttpUrlConnection officially recommended is used after 2.3.

Another important thing isVolley cache MethodThe request results are cached Based on the Cache control Header returned by the server during the request. The next request determines that if the request does not expire, the cache will be used to speed up the response, if you need to refresh the page again, if the server returns 304, it indicates that the requested resource has not changed since the last request cache. In this case, you do not need to refresh the page again with the cache, however, this requires server support.

After caching the last request, the request can be successful even if there is no network in the next request. The key is,The cache processing is completely transparent to users. In some simple cases, some cache-related tasks will be omitted.


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.