1a89ae4cdc
Change-Id: Ife3a9a64439e07aaaf92a22adc6d1678138caf7d
282 lines
11 KiB
Plaintext
282 lines
11 KiB
Plaintext
page.title=Making a Standard Request
|
|
|
|
trainingnavtop=true
|
|
|
|
@jd:body
|
|
|
|
<div id="tb-wrapper">
|
|
<div id="tb">
|
|
|
|
<!-- table of contents -->
|
|
<h2>This lesson teaches you to</h2>
|
|
<ol>
|
|
<li><a href="#request-image">Request an Image</a></li>
|
|
<li><a href="#request-json">Request JSON</a></li>
|
|
</ol>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
<a class="notice-developers-video wide" href="https://developers.google.com/events/io/sessions/325304728">
|
|
<div>
|
|
<h3>Video</h3>
|
|
<p>Volley: Easy, Fast Networking for Android</p>
|
|
</div>
|
|
</a>
|
|
|
|
<p>
|
|
This lesson describes how to use the common request types that Volley supports:</p>
|
|
|
|
<ul>
|
|
<li>{@code StringRequest}. Specify a URL and receive a raw string in response. See
|
|
<a href="requestqueue.html">Setting Up a Request Queue</a> for an example.</li>
|
|
<li>{@code ImageRequest}. Specify a URL and receive an image in response.</li>
|
|
<li>{@code JsonObjectRequest} and {@code JsonArrayRequest} (both subclasses of
|
|
{@code JsonRequest}). Specify a URL and get a JSON object or array (respectively) in
|
|
response.</li>
|
|
</ul>
|
|
|
|
<p>If your expected response is one of these types, you probably won't have to implement a
|
|
custom request. This lesson describes how to use these standard request types. For
|
|
information on how to implement your own custom request, see <a href="requests-custom.html">
|
|
Implementing a Custom Request</a>.</p>
|
|
|
|
|
|
<h2 id="request-image">Request an Image</h2>
|
|
|
|
<p>Volley offers the following classes for requesting images. These classes layer on top
|
|
of each other to offer different levels of support for processing images:</p>
|
|
|
|
<ul>
|
|
<li>{@code ImageRequest}—a canned request for getting an image at a given URL and
|
|
calling back with a decoded bitmap. It also provides convenience features like specifying
|
|
a size to resize to. Its main benefit is that Volley's thread scheduling ensures that
|
|
expensive image operations (decoding, resizing) automatically happen on a worker thread.</li>
|
|
|
|
<li>{@code ImageLoader}—a helper class that handles loading and caching images from
|
|
remote URLs. {@code ImageLoader} is a an orchestrator for large numbers of {@code ImageRequest}s,
|
|
for example when putting multiple thumbnails in a {@link android.widget.ListView}.
|
|
{@code ImageLoader} provides an in-memory cache to sit in front of the normal Volley
|
|
cache, which is important to prevent flickering. This makes it possible to achieve a
|
|
cache hit without blocking or deferring off the main thread, which is impossible when
|
|
using disk I/O. {@code ImageLoader} also does response coalescing, without which almost
|
|
every response handler would set a bitmap on a view and cause a layout pass per image.
|
|
Coalescing makes it possible to deliver multiple responses simultaneously, which improves
|
|
performance.</li>
|
|
<li>{@code NetworkImageView}—builds on {@code ImageLoader} and effectively replaces
|
|
{@link android.widget.ImageView} for situations where your image is being fetched over
|
|
the network via URL. {@code NetworkImageView} also manages canceling pending requests if
|
|
the view is detached from the hierarchy.</li>
|
|
</ul>
|
|
|
|
<h3>Use ImageRequest</h3>
|
|
|
|
<p>Here is an example of using {@code ImageRequest}. It retrieves the image specified by
|
|
the URL and displays it in the app. Note that this snippet interacts with the
|
|
{@code RequestQueue} through a singleton class (see <a href="{@docRoot}
|
|
training/volley/requestqueue.html#singleton">Setting Up a RequestQueue</a> for more discussion of
|
|
this topic):</p>
|
|
|
|
<pre>
|
|
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<Bitmap>() {
|
|
@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);</pre>
|
|
|
|
|
|
<h3>Use ImageLoader and NetworkImageView</h3>
|
|
|
|
<p>You can use {@code ImageLoader} and {@code NetworkImageView} in concert to efficiently
|
|
manage the display of multiple images, such as in a {@link android.widget.ListView}. In your
|
|
layout XML file, you use {@code NetworkImageView} in much the same way you would use
|
|
{@link android.widget.ImageView}, for example:</p>
|
|
|
|
<pre><com.android.volley.toolbox.NetworkImageView
|
|
android:id="@+id/networkImageView"
|
|
android:layout_width="150dp"
|
|
android:layout_height="170dp"
|
|
android:layout_centerHorizontal="true" /></pre>
|
|
|
|
<p>You can use {@code ImageLoader} by itself to display an image, for example:</p>
|
|
|
|
<pre>
|
|
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));
|
|
</pre>
|
|
|
|
<p>However, {@code NetworkImageView} can do this for you if all you're doing is populating
|
|
an {@link android.widget.ImageView}. For example:</p>
|
|
|
|
<pre>
|
|
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);
|
|
</pre>
|
|
|
|
<p>The above snippets access the {@code RequestQueue} and the {@code ImageLoader}
|
|
through a singleton class, as described in <a href="{@docRoot}training/volley/requestqueue.html#singleton">
|
|
Setting Up a RequestQueue</a>. This approach ensures that your app creates single instances of
|
|
these classes that last the lifetime of your app. The reason that this is important for
|
|
{@code ImageLoader} (the helper class that handles loading and caching images) is that
|
|
the main function of the in-memory cache is to allow for flickerless rotation. Using a
|
|
singleton pattern allows the bitmap cache to outlive the activity. If instead you create the
|
|
{@code ImageLoader} in an activity, the {@code ImageLoader} would be recreated along with
|
|
the activity every time the user rotates the device. This would cause flickering.</p>
|
|
|
|
<h4 id="lru-cache">Example LRU cache</h4>
|
|
|
|
<p>The Volley toolbox provides a standard cache implementation via the
|
|
{@code DiskBasedCache} class. This class caches files directly onto the hard disk in the
|
|
specified directory. But to use {@code ImageLoader}, you should provide a custom
|
|
in-memory LRU bitmap cache that implements the {@code ImageLoader.ImageCache} interface.
|
|
You may want to set up your cache as a singleton; for more discussion of this topic, see
|
|
<a href="{@docRoot}training/volley/requestqueue.html#singleton">
|
|
Setting Up a RequestQueue</a>.</p>
|
|
|
|
<p>Here is a sample implementation for an in-memory {@code LruBitmapCache} class.
|
|
It extends the {@link android.support.v4.util.LruCache} class and implements the
|
|
{@code ImageLoader.ImageCache} interface:</p>
|
|
|
|
<pre>
|
|
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;
|
|
}
|
|
}
|
|
</pre>
|
|
|
|
<p>Here is an example of how to instantiate an {@code ImageLoader} to use this
|
|
cache:</p>
|
|
|
|
<pre>
|
|
RequestQueue mRequestQueue; // assume this exists.
|
|
ImageLoader mImageLoader = new ImageLoader(mRequestQueue, new LruBitmapCache(
|
|
LruBitmapCache.getCacheSize()));
|
|
</pre>
|
|
|
|
|
|
<h2 id="request-json">Request JSON</h2>
|
|
|
|
<p>Volley provides the following classes for JSON requests:</p>
|
|
|
|
<ul>
|
|
<li>{@code JsonArrayRequest}—A request for retrieving a
|
|
{@link org.json.JSONArray}
|
|
response body at a given URL.</li>
|
|
<li>{@code JsonObjectRequest}—A request for retrieving a
|
|
{@link org.json.JSONObject}
|
|
response body at a given URL, allowing for an optional
|
|
{@link org.json.JSONObject}
|
|
to be passed in as part of the request body.</li>
|
|
</ul>
|
|
|
|
<p>Both classes are based on the common base class {@code 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:</p>
|
|
|
|
<pre>
|
|
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<JSONObject>() {
|
|
|
|
@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);
|
|
</pre>
|
|
|
|
For an example of implementing a custom JSON request based on
|
|
<a href="http://code.google.com/p/google-gson/">Gson</a>, see the next lesson,
|
|
<a href="request-custom.html">Implementing a Custom Request</a>.
|