Transmitting Network Data Using Volley

Volley is an HTTP library that makes navigating the web in Android applications easier, more important, and faster. Volley is an “open source project.” .

Volley offers the following benefits:

  • Automated network request scheduling.
  • Multiple concurrent network connections.
  • Hard disk and memory response caching for standard HTTP transparency. cache coherence.
  • Support the priority of requests.
  • An API that supports request termination. You can terminate a single request, or a number of requests within a range, or within a period of a request.
  • Easy customizations, such as retry and rollback.
  • Strong ordering, which makes it easier to properly handle UI and extract data asynchronously when operating on the network.
  • Debugging and tracing tools. .

The RPC-type (remote procedure call) operations Volley specializes in used to be used to populate the UI, such as extracting a page of search results as structured data. It is easier to integrate with other protocols, and has excellent support for raw strings, images, and JSON. With built-in support for features you want,Volley frees you from boilerplate code and lets you focus on the details of your business.

Volley is not suitable for large file downloads or streaming operations because Volley holds all the response content in memory during parsing. If you want a large file download operation, consider using an alternative, such as DownloadManager.

 

The core Volley package is open to frameworks/ Volley under the AOSP project and contains the main request scheduling channels, similar to the common application enterprise, available in Volley “toolbox.” The easiest way to add Volley to your project is to clone the Volley repository and make it your project’s library project:

  1. Clone the Volley repository with Git and type the following at your command prompt:

    git clone https://android.googlesource.com/platform/frameworks/volley
    Copy the code
  2. Import the downloaded source code into your project and use it as your library project (if you use Eclipse, read Managing Projects from Eclipse with ADT for more descriptions) or compile it into a.jar file.

 

course


    • Send a simple request (Sending a Simple Request)
    • Learn how to send a simple request using Volley’s default behavior and how to terminate a request.
    • Set up the request queue (Setting Up a RequestQueue)
    • Learn how to set up a request queue and how to use a singleton pattern to create a request queue consistent with the life cycle of your App.
    • Construct a standard request (Making a Standard Request)
    • Learn how to send a request using Volley’s out-of-the-box request types (such as raw string, image, JSON).
    • Implementing custom requests (Implementing a Custom Request)
    • Learn how to implement custom requests.

 

Sending a Simple Request

At a high level, you use Volley to create a request queue and pass in a request object as a parameter. The request queue is responsible for managing worker threads to initiate network operations, read and write to the cache, and parse responses. The request performs parsing of the original response, and Volley carefully distributes the parsed response to the main thread.

This tutorial describes how to send a request using the convenient method volley. newRequestQueue. It configures a request queue for you. You can learn how to configure a RequestQueue by studying the next lesson, “Setting Up a RequestQueue”.

This lesson also describes how to add a request to a message queue, and terminate a request.

Add the INTERNET Permission.

To use the Volley, you must be in your manifest file to add an android. Permission. INTERNET access. Without this, your app won’t be able to access the web.

Using newRequestQueue

Volley provides a convenient method volley. newRequestQueue to configure a message queue, use default values, and start the queue, for example:

final TextView mTextView = (TextView) findViewById(R.id.text); . // Instantiate the RequestQueue. RequestQueue queue = Volley.newRequestQueue(this); String url ="http://www.google.com"; // Request a string response from the provided URL. StringRequest stringRequest = new StringRequest(Request.Method.GET, url, new Response.Listener() { @Override public void onResponse(String response) { // Display the first 500 characters of the Response string.mtextview.settext (" response is: "+ response.substring(0,500)); }}, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { mTextView.setText("That didn't  work!" ); }}); // Add the request to the RequestQueue. queue.add(stringRequest);Copy the code

Volley always passes parsed responses to the main thread. The advantage of running on the main thread is that it is very convenient to use received data to notify UI controls, just as you are free to modify UI controls directly in your response handler, but the semantics provided by the class library are particularly important, especially when associated with cancellation requests.

Read the section Setting Up a RequestQueue for more information about Setting Up a RequestQueue, which can be used as an alternative to the convenience of volley. newRequestQueue.

Send a Request

To send a request, you can simply construct a request and add it to the request queue using the add() method, as described above. Once you add the request, it is moved through the pipeline, served, and received with the original response and delivered.

When you call the add() method, Volley starts a cache processing thread and a network distribution thread pool. When you add a request to the queue, it is picked up and sorted by the cache thread: if the request can be served from the cache, the original response content from the cache is parsed in the cache process, and the parsed response content is passed to the main thread. If the request cannot be served from the cache, it is placed in the network queue. The first active network thread picks it up from the queue, handles the HTTP transfer, parses the response contents in the worker thread, writes the response contents to the cache, and sends the parsed response to the main thread.

Note that expensive operations, such as blocking I/O, and parsing/decoding, are done in worker threads. You can add requests to any thread, but the response is always passed to the main thread.

Figure 1 illustrates the lifecycle of a request:

 

Figure 1. Request lifecycle.

Interrupt a Request (Cancel a Request)

To interrupt a request, call the cancel() method on your request object. Once interrupted, Volley ensures that your response handler is never called. The practical meaning is that you can interrupt your waiting requests in the onStop() method of your activity, and you won’t be forced to mess around with your request handler, such as checking to see if getActivity() == null, onSaveInstanceState() has been called, Or other defensive boilerplate code.

To reap the benefits of this behavior, you typically have to keep track of all in-flight requests in order to terminate them at the appropriate time. There’s an easier way to do this: you can associate a label object with each request. You can use this tag to provide a range of requests that can be interrupted. For example, you can mark all your requests with the Activity object and call requestQueue.cancelAll(this) on onStop(). Similarly, you can mark all of their own thumbnail requests with their respective TAB objects in a ViewPager TAB and trigger termination when switching to ensure that the new TAB objects are not held by requests from other tabs.

Here is an example of using string values as labels:

  1. Define your tag and add it to your request.

    public static final String TAG = "MyTag";
    StringRequest stringRequest; // Assume this exists.
    RequestQueue mRequestQueue;  // Assume this exists.
    
    // Set the tag on the request.
    stringRequest.setTag(TAG);
    
    // Add the request to the RequestQueue.
    mRequestQueue.add(stringRequest);
    Copy the code
  2. In your activity’s onStop() method, terminate all requests marked with this tag.

    @Override
    protected void onStop () {
        super.onStop();
        if (mRequestQueue != null) {
            mRequestQueue.cancelAll(TAG);
        }
    }
    Copy the code

Be very careful when calling termination requests. Remember this if you rely on your response handler to change a state or kick out some steps. Again, corresponding processing is never called after termination.

 

 

Setting Up a RequestQueue

Last lesson showed how to use the convenient method volley. newRequestQueue to set up a request queue to take advantage of the default behavior provided by Volley. This lesson teaches you how to create a request queue through specific steps that you can customize.

This lesson also describes the recommended practice of using the singleton pattern to create a request queue that lasts for the entire life of the App.

Set Up a Network and Cache

A request queue needs two things to do its job: a network object to handle the transfer of requests, and a cache object to handle the cache. There are already implementations of the two standards available in the Volley toolbox: DiskBasedCache provides a “one-file-per-response” cache with in-memory indexing; The BasicNetwork object provides network transport based on the AndroidHttpClient or HttpURLConnection object of your choice.

BasicNetwork is the default network implementation of Volley. A BasicNetwork object must be initialized using an HTTP client before it can connect to the network. AndroidHttpClient or HttpURLConnection:

  • In Android API Level 9 (Gingerbread) below, useAndroidHttpClient. Before the Gingerbread,HttpURLConnectionIs unreliable. Read moreAndroid’s HTTP Clients.
  • On Android API Level 9 (Gingerbread) and later, useHttpURLConnection .

To create an application that runs on all versions of Android, you can check the version number of Android running on the Android hardware to select the HTTP client, for example:

HttpStack stack;
...
// If the device is running a version >= Gingerbread...
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
    // ...use HttpURLConnection for stack.
} else {
    // ...use AndroidHttpClient for stack.
}
Network network = new BasicNetwork(stack);
Copy the code

This code snippet shows the steps to set up the request queue:

RequestQueue mRequestQueue; // Instantiate the cache Cache cache = new DiskBasedCache(getCacheDir(), 1024 * 1024); // 1MB cap // Set up the network to use HttpURLConnection as the HTTP client. Network network = new BasicNetwork(new HurlStack()); // Instantiate the RequestQueue with the cache and network. mRequestQueue = new RequestQueue(cache, network); // Start the queue mRequestQueue.start(); String url ="http://www.myurl.com"; // Formulate the request and handle the response. StringRequest stringRequest = new StringRequest(Request.Method.GET, url, new Response.Listener<String>() { @Override public void onResponse(String response) { // Do something with the response } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { // Handle error } }); // Add the request to the RequestQueue. mRequestQueue.add(stringRequest); .Copy the code

If you only need to build a single request and don’t want to leave the thread pool, you can create a request queue anywhere and call the stop() method when a response or error is received. See Sending a Simple Request for the method volley.newRequestQueue (). But a more common use case is to use the singleton pattern to create a request queue and align it with the life cycle of your application, which is described in the next section.

Use a Singleton Pattern

If your application requires frequent network access, it is very efficient to configure a singleton request queue and maintain it throughout the life of your app. You can do this in a couple of ways. The recommended approach is to implement a singleton class that encapsulates the request queue and other Volley function methods/functions. Alternative implementations such as subclasses of Applicaton and configuring the request queue in the application.oncreate () method are now discouraged; A static singleton can provide the same functionality in a modular manner.

A key concept is that the request queue must be initialized using the Application context object, not the Activity context. This ensures that the request queue lasts throughout the life of the app, and that the implementation of the Activity context is created multiple times when the activity is recreated (for example, the activity is recreated when the user rotates the screen).

Here is an example of a class that implements the singleton pattern and provides the request queue and ImageLoader functionality:

private static MySingleton mInstance; private RequestQueue mRequestQueue; private ImageLoader mImageLoader; private static Context mCtx; private MySingleton(Context context) { mCtx = context; mRequestQueue = getRequestQueue(); mImageLoader = new ImageLoader(mRequestQueue, new ImageLoader.ImageCache() { private final LruCache<String, Bitmap> cache = new LruCache<String, Bitmap>(20); @Override public Bitmap getBitmap(String url) { return cache.get(url); } @Override public void putBitmap(String url, Bitmap bitmap) { cache.put(url, bitmap); }}); } public static synchronized MySingleton getInstance(Context context) { if (mInstance == null) { mInstance = new MySingleton(context); } return mInstance; } public RequestQueue getRequestQueue() { if (mRequestQueue == null) { // getApplicationContext() is key, it keeps you from leaking the // Activity or BroadcastReceiver if someone passes one in. mRequestQueue = Volley.newRequestQueue(mCtx.getApplicationContext()); } return mRequestQueue; } public <T> void addToRequestQueue(Request<T> req) { getRequestQueue().add(req); } public ImageLoader getImageLoader() { return mImageLoader; }}Copy the code

Here is an example of using a singleton class to handle request queue operations:

// Get a RequestQueue RequestQueue queue = MySingleton.getInstance(this.getApplicationContext()). getRequestQueue(); . // Add a request (in this example, called stringRequest) to your RequestQueue. MySingleton.getInstance(this).addToRequestQueue(stringRequest);Copy the code

 

 

 

Making a Standard Request

This lesson describes how to use the general request types provided by Volley:

  • StringRequest. Specify a URL and receive a raw string in the corresponding field. inSetting Up a Request QueueWith the sample.
  • ImageRequest. Specify a web address (URL) and receive the image in the response.
  • JsonObjectRequest 和 JsonArrayRequest(allJsonRequest subclassesSpecify a URL and get a JSON object or JSON array.

If you expect one of these responses, you may no longer need to implement a custom request. This lesson describes how to use these standard request types. For more information on Custom requests, see Implementing a Custom Request.

Request an Image

Volley provides the following classes to request images, which are at the top of each other’s hierarchy and provide varying degrees of support for processing images:

  • ImageRequest (ImageRequest)– an encapsulated request to retrieve an image from the specified URL and to call back after decoding the image. It also provides convenience features such as specifying a size to be adjusted to. To its advantage, Volley’s thread scheduling ensures that expensive image operations (decoding, resizing, etc.) are performed automatically in the worker thread.
  • ImageLoader (Image download)– a helper class that handles loading and caching images from multiple remote image addresses. ImageLoader is a console that handles a large number of image requests, such as placing multiple thumbnails in a ListView. ImageLoader provides an in-memory cache on top of Volley’s usual cache, which is important to prevent flickering. This provides the possibility to achieve a cache hit without blocking or delay in the main thread, which is not possible with hard disk I/O. ImageLoader also does response merge, without which almost every response handler displays an image on a View and causes a layout action for each image. Merging makes it possible to pass multiple responses simultaneously, which improves performance.
  • NetworkImageView– toImageLoader based andEffective substitutionImageViewIn some cases, such as when your image is extracted from a web site. NetworkImageView also manages requests to terminate waiting when a NetworkImageView is detached from the view hierarchy.

Use ImageRequest

Here is an example using ImageRequest. It takes the image from a URL and displays it in the app. Notice the interaction with the request queue using the singleton pattern. (Read Setting Up a RequestQueue for more on this topic):

ImageView mImageView; String url = "http://i.imgur.com/7spzG.png"; mImageView = (ImageView) findViewById(R.id.myImage); . // Retrieves an image specified by the URL, displays it in the UI. ImageRequest request = new ImageRequest(url, new Response.Listener() { @Override public void onResponse(Bitmap bitmap) { mImageView.setImageBitmap(bitmap); } }, 0, 0, null, new Response.ErrorListener() { public void onErrorResponse(VolleyError error) { mImageView.setImageResource(R.drawable.image_load_error); }}); // Access the RequestQueue through your singleton class. MySingleton.getInstance(this).addToRequestQueue(request);Copy the code

Use ImageLoader and NetworkImageView.

You can use ImageLoader and NetworkImageView to coordinate and efficiently manage the display of large numbers of images, such as in ListView. Using NetworkImageView in your layout XML file is very similar to using ImageView, for example:

<com.android.volley.toolbox.NetworkImageView
        android:id="@+id/networkImageView"
        android:layout_width="150dp"
        android:layout_height="170dp"
        android:layout_centerHorizontal="true" />
Copy the code

You can use ImageLoader to display an image by itself, for example:

ImageLoader mImageLoader; ImageView mImageView; // The URL for the image that is being loaded. private static final String IMAGE_URL = "http://developer.android.com/images/training/system-ui.png"; . mImageView = (ImageView) findViewById(R.id.regularImageView); // Get the ImageLoader through your singleton class. mImageLoader = MySingleton.getInstance(this).getImageLoader(); mImageLoader.get(IMAGE_URL, ImageLoader.getImageListener(mImageView, R.drawable.def_image, R.drawable.err_image));Copy the code

However, if all you need to do is display the image in the ImageView, NetworkImageView can do this as well, for example:

ImageLoader mImageLoader; NetworkImageView mNetworkImageView; private static final String IMAGE_URL = "http://developer.android.com/images/training/system-ui.png"; . // Get the NetworkImageView that will display the image. mNetworkImageView = (NetworkImageView) findViewById(R.id.networkImageView); // Get the ImageLoader through your singleton class. mImageLoader = MySingleton.getInstance(this).getImageLoader(); // Set the URL of the image that should be loaded into this view, and // specify the ImageLoader that will be used to make the request. mNetworkImageView.setImageUrl(IMAGE_URL, mImageLoader);Copy the code

The code snippet above shows how a singleton class can access the RequestQueue and ImageLoader. See Setting Up a RequestQueue for more information. This ensures that you create single instances of these classes that last throughout the life of your App. This is important because for ImageLoader (the helper class that handles reading and caching images), the main feature of the in-memory cache is that it does not flicker when flipping the screen. Using a singleton pattern allows bitmap caches to outlive activities. If you create an ImageLoader in your Activity, the ImageLoader will follow the Activity and be recreated every time the user flips the device and the screen flashes.

LRU cache Example LRU cache

The Volley tool box provides an implementation of a standard cache based on the DiskBasedCache class. This class caches a file directly to a specified folder on the hard disk. But to use ImageDownloader, you need to provide a custom in-memory LRU bitmap cache and implement the ImageLoader.ImageCache interface. You can use singleton classes to set up your cache; Read Setting Up a RequestQueue for more discussion.

The LruBitmapCache class below is an example of an implementation. It inherits from LruCache and implements ImageLoader.ImageCache interface:

import android.graphics.Bitmap; import android.support.v4.util.LruCache; import android.util.DisplayMetrics; import com.android.volley.toolbox.ImageLoader.ImageCache; public class LruBitmapCache extends LruCache<String, Bitmap> implements ImageCache { public LruBitmapCache(int maxSize) { super(maxSize); } public LruBitmapCache(Context ctx) { this(getCacheSize(ctx)); } @Override protected int sizeOf(String key, Bitmap value) { return value.getRowBytes() * value.getHeight(); } @Override public Bitmap getBitmap(String url) { return get(url); } @Override public void putBitmap(String url, Bitmap bitmap) { put(url, bitmap); } // Returns a cache size equal to approximately three screens worth of images. public static int getCacheSize(Context ctx) { final DisplayMetrics displayMetrics = ctx.getResources(). getDisplayMetrics(); final int screenWidth = displayMetrics.widthPixels; final int screenHeight = displayMetrics.heightPixels; // 4 bytes per pixel final int screenBytes = screenWidth * screenHeight * 4; return screenBytes * 3; }}Copy the code

The following shows how to instantiate an ImageLoader and use the cache:

RequestQueue mRequestQueue; // assume this exists.
ImageLoader mImageLoader = new ImageLoader(mRequestQueue, new LruBitmapCache(
            LruBitmapCache.getCacheSize()));
Copy the code

Request JSON (Request JSON)

Volley provides the following classes for JSON requests:

  • JsonArrayRequest – With a specified URL, send a request to get oneJSONArray(JSON array) response body.
  • JsonObjectRequest – With a specified URL, send a request to get oneJSONObject(JSON object) response body, which allows an optionalJSONObjectObjects are passed as parameters as part of the request body.

These classes are based on the general base class JsonRequest. You can use them just like any other type of request, for example, the following example shows extracting a JSON feed and displaying it as text in the UI.

Both classes are based on the common base class JsonRequest. You use them following the same basic pattern you use for Other types of requests. For example, this snippet fetches a JSON feed and displays it as text in the UI:

TextView mTxtDisplay; ImageView mImageView; mTxtDisplay = (TextView) findViewById(R.id.txtDisplay); String url = "http://my-json-feed"; JsonObjectRequest jsObjRequest = new JsonObjectRequest (Request.Method.GET, url, null, new Response.Listener() { @Override public void onResponse(JSONObject response) { mTxtDisplay.setText("Response: " + response.toString()); }}, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { // TODO Auto-generated method stub } }); // Access the RequestQueue through your singleton class. MySingleton.getInstance(this).addToRequestQueue(jsObjRequest);Copy the code

For an example of an intern Custom JSON Request based on Gson, read the next lesson, Implementing a Custom Request.

 

 

Implementing a Custom Request (Implementing a Custom Request)

This tutorial describes how to implement your custom request types that are not included in the out-of-the-box types supported by Volley.

Write a Custom Request

In the tool box, there are many requests that are ready-to-use; If your response is a string, image, or JSON, you may not need to implement a custom request.

 

In those cases where you want to implement a custom request, here’s what you need to do:

  • inheritanceRequest<T>Class, right here<T>Represents the type to which your request is expected to resolve. If your parsed response is a String, for example, create your custom Request by inheriting Request<String>. See more classes in the Volley toolbox for detailsStringRequest 和 ImageRequestAn example inherited from Request<T>.
  • Implement the abstract methods parseNetworkResponse() and deliverResponse(), described in more detail below.

Parsing network Requests (parseNetworkResponse)

A response encapsulates a parsed response for transmission, for a specified type (such as string, image, or JSON). Here is an example of implementing parseNetworkResponse() :

@Override
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));
    }
    // handle errors
...
}
Copy the code

Note the following:

  • parseNetworkResponse()There is one parameterNetworkResponse, which contains the response loaded with the byte array byte[], the HTTP status code, and the response header.
  • Your implementation must return oneResponse<T>, which contains your typed (strongly typed) response object and cache metadata, or errors if parsing fails

If your protocol contains non-standard semantics, you can create your own cache.entry, but most requests like this work well:

return Response.success(myDecodedObject,
        HttpHeaderParser.parseCacheHeaders(response));
Copy the code

Volley calls parseNetworkResponse() in a work scene. This ensures that expensive parsing operations such as decoding a JPEG image into a bitmap object do not block the UI thread.

Delivery Response

Volley calls back to the main thread using the object returned in your parseNetworkResponse(). Many requests invoke the callback interface here, for example:

protected void deliverResponse(T response) {
        listener.onResponse(response);
Copy the code

GsonRequest (Example: GsonRequest)

Gson is a class library that uses reflective methods to convert Java objects and JSON to each other. You can define a Java object with fields with the same names as those JSON key names. Pass the object of the class to GSON, and GSON will automatically fill in the values of these fields for you. Here is a complete implementation of a Volley request parsed using GSON:

public class GsonRequest<T> extends Request<T> { private final Gson gson = new Gson(); private final Class<T> clazz; private final Map<String, String> headers; private final Listener<T> listener; /** * Make a GET request and return a parsed object from JSON. * * @param url URL of the request to make * @param clazz Relevant class object, for Gson's reflection * @param headers Map of request headers */ public GsonRequest(String url, Class<T> clazz, Map<String, String> headers, Listener<T> listener, ErrorListener errorListener) { super(Method.GET, url, errorListener); this.clazz = clazz; this.headers = headers; this.listener = listener; } @Override public Map<String, String> getHeaders() throws AuthFailureError { return headers ! = null ? headers : super.getHeaders(); } @Override protected void deliverResponse(T response) { listener.onResponse(response); } @Override 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)); }}}Copy the code

Volley provides ready-to-use JsonArrayRequest and JsonArrayObject classes, if you prefer that way. Read Using Standard Request Types for more information.

  

(Full text)