am ea5fa98c: am c659e746: Merge "Doc update: new Volley class" into klp-docs

* commit 'ea5fa98c7c381a37c113b7d2efdd6a406d902949':
  Doc update: new Volley class
This commit is contained in:
Katie McCormick
2014-06-04 12:32:09 +00:00
committed by Android Git Automerger
11 changed files with 3267 additions and 0 deletions

19
\ Normal file
View File

@ -0,0 +1,19 @@
Doc update: new Volley class
Change-Id: Ife3a9a64439e07aaaf92a22adc6d1678138caf7d
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# On branch volley
# Changes to be committed:
# new file: docs/html/images/training/volley-request.png
# modified: docs/html/training/basics/network-ops/connecting.jd
# modified: docs/html/training/basics/network-ops/index.jd
# modified: docs/html/training/training_toc.cs
# new file: docs/html/training/volley/index.jd
# new file: docs/html/training/volley/request-custom.jd
# new file: docs/html/training/volley/request.jd
# new file: docs/html/training/volley/requestqueue.jd
# new file: docs/html/training/volley/setup.jd
# new file: docs/html/training/volley/simple.jd
#

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

View File

@ -25,6 +25,7 @@ next.link=managing.html
<h2>You should also read</h2> <h2>You should also read</h2>
<ul> <ul>
<li><a href="{@docRoot}training/volley/index.html">Transmitting Network Data Using Volley</a></li>
<li><a href="{@docRoot}training/monitoring-device-state/index.html">Optimizing Battery Life</a></li> <li><a href="{@docRoot}training/monitoring-device-state/index.html">Optimizing Battery Life</a></li>
<li><a href="{@docRoot}training/efficient-downloads/index.html">Transferring Data Without Draining the Battery</a></li> <li><a href="{@docRoot}training/efficient-downloads/index.html">Transferring Data Without Draining the Battery</a></li>
<li><a href="{@docRoot}guide/webapps/index.html">Web Apps Overview</a></li> <li><a href="{@docRoot}guide/webapps/index.html">Web Apps Overview</a></li>

View File

@ -24,6 +24,7 @@ next.link=connecting.html
<li><a href="{@docRoot}training/monitoring-device-state/index.html">Optimizing Battery Life</a></li> <li><a href="{@docRoot}training/monitoring-device-state/index.html">Optimizing Battery Life</a></li>
<li><a href="{@docRoot}training/efficient-downloads/index.html">Transferring Data Without Draining the Battery</a></li> <li><a href="{@docRoot}training/efficient-downloads/index.html">Transferring Data Without Draining the Battery</a></li>
<li><a href="{@docRoot}guide/webapps/index.html">Web Apps Overview</a></li> <li><a href="{@docRoot}guide/webapps/index.html">Web Apps Overview</a></li>
<li><a href="{@docRoot}training/volley/index.html">Transmitting Network Data Using Volley</a></li>
</ul> </ul>
@ -51,6 +52,14 @@ as a source of reusable code for your own application.</p>
fundamental building blocks for creating Android applications that download fundamental building blocks for creating Android applications that download
content and parse data efficiently, while minimizing network traffic.</p> content and parse data efficiently, while minimizing network traffic.</p>
<p class="note"><strong>Note:</strong> See the class <a href="{@docRoot}
training/volley/index.html">Transmitting Network Data Using Volley</a>
for information on Volley, an HTTP library that makes networking for Android apps
easier and faster. Volley is available through the open
<a href="https://android.googlesource.com/platform/frameworks/volley">AOSP</a>
repository. Volley may be able to help you streamline and improve the performance
of your app's network operations.</p>
<h2>Lessons</h2> <h2>Lessons</h2>

View File

@ -609,6 +609,35 @@ include the action bar on devices running Android 2.1 or higher."
</li> </li>
</ul> </ul>
</li> </li>
<li class="nav-section">
<div class="nav-section-header">
<a href="<?cs var:toroot ?>training/volley/index.html"
description="How to perform fast, scalable UI operations over the network using Volley"
>Transmitting Network Data Using Volley</a>
</div>
<ul>
<li>
<a href="<?cs var:toroot ?>training/volley/simple.html">
Sending a Simple Request
</a>
</li>
<li>
<a href="<?cs var:toroot ?>training/volley/requestqueue.html">
Setting Up a RequestQueue
</a>
</li>
<li>
<a href="<?cs var:toroot ?>training/volley/request.html">
Making a Standard Request
</a>
</li>
<li>
<a href="<?cs var:toroot ?>training/volley/request-custom.html">
Implementing a Custom Request
</a>
</li>
</ul>
</li>
</ul> </ul>
</li> </li>

View File

@ -0,0 +1,133 @@
page.title=Transmitting Network Data Using Volley
page.tags=""
trainingnavtop=true
startpage=true
@jd:body
<div id="tb-wrapper">
<div id="tb">
<!-- Required platform, tools, add-ons, devices, knowledge, etc. -->
<h2>Dependencies and prerequisites</h2>
<ul>
<li>Android 1.6 (API Level 4) or higher</li>
</ul>
<h2>You should also see</h2>
<ul>
<li>For a production quality app that uses Volley, see the 2013 Google I/O
<a href="https://github.com/google/iosched">schedule app</a>. In particular, see:
<ul>
<li><a
href="https://github.com/google/iosched/blob/master/android/src/main/java/com/google/android/apps/iosched/util/ImageLoader.java">
ImageLoader</a></li>
<li><a
href="https://github.com/google/iosched/blob/master/android/src/main/java/com/google/android/apps/iosched/util/BitmapCache.java">
BitmapCache</a></li>
</ul>
</li>
</ul>
</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>Volley is an HTTP library that makes networking for Android apps easier and most importantly,
faster. Volley is available through the open
<a href="https://android.googlesource.com/platform/frameworks/volley">AOSP</a> repository.</p>
<p>Volley offers the following benefits:</p>
<ul>
<li>Automatic scheduling of network requests.</li>
<li>Multiple concurrent network connections.</li>
<li>Transparent disk and memory response caching with standard HTTP
<a href=http://en.wikipedia.org/wiki/Cache_coherence">cache coherence</a>.</li>
<li>Support for request prioritization.</li>
<li>Cancellation request API. You can cancel a single request, or you can set blocks or
scopes of requests to cancel.</li>
<li>Ease of customization, for example, for retry and backoff.</li>
<li>Strong ordering that makes it easy to correctly populate your UI with data fetched
asynchronously from the network.</li>
<li>Debugging and tracing tools.</li>
</ul>
<p>Volley excels at RPC-type operations used to populate a UI, such as fetching a page of
search results as structured data. It integrates easily with any protocol and comes out of
the box with support for raw strings, images, and JSON. By providing built-in support for
the features you need, Volley frees you from writing boilerplate code and allows you to
concentrate on the logic that is specific to your app.</p>
<p>Volley is not suitable for large download or streaming operations, since Volley holds
all responses in memory during parsing. For large download operations, consider using an
alternative like {@link android.app.DownloadManager}.</p>
<p>The core Volley library is developed in the open
<a href="https://android.googlesource.com/platform/frameworks/volley">AOSP</a>
repository at {@code frameworks/volley} and contains the main request dispatch pipeline
as well as a set of commonly applicable utilities, available in the Volley "toolbox." The
easiest way to add Volley to your project is to clone the Volley repository and set it as
a library project:</p>
<ol>
<li>Git clone the repository by typing the following at the command line:
<pre>
git clone https://android.googlesource.com/platform/frameworks/volley
</pre>
</li>
<li>Import the downloaded source into your app project as an Android library project
(as described in <a href="{@docRoot}tools/projects/projects-eclipse.html">
Managing Projects from Eclipse with ADT</a>, if you're using Eclipse) or make a
<a href="{@docRoot}guide/faq/commontasks.html#addexternallibrary"><code>.jar</code> file</a>.</li>
</ol>
<h2>Lessons</h2>
<dl>
<dt>
<strong><a href="simple.html">Sending a Simple Request</a></strong>
</dt>
<dd>
Learn how to send a simple request using the default behaviors of Volley, and how
to cancel a request.
</dd>
<dt>
<strong><a href="requestqueue.html">Setting Up a RequestQueue</a></strong>
</dt>
<dd>
Learn how to set up a {@code RequestQueue}, and how to implement a singleton
pattern to create a {@code RequestQueue} that lasts the lifetime of your app.
</dd>
<dt>
<strong><a href="request.html">Making a Standard Request</a></strong>
</dt>
<dd>
Learn how to send a request using one of Volley's out-of-the-box request types
(raw strings, images, and JSON).
</dd>
<dt>
<strong><a href="request-custom.html">Implementing a Custom Request</a></strong>
</dt>
<dd>
Learn how to implement a custom request.
</dd>
</dl>

View File

@ -0,0 +1,163 @@
page.title=Implementing a Custom 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="#custom-request">Write a Custom Request</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 implement your own custom request types, for types that
don't have out-of-the-box Volley support.</p>
<h2 id="custom-request">Write a Custom Request</h2>
Most requests have ready-to-use implementations in the toolbox; if your response is a string,
image, or JSON, you probably won't need to implement a custom {@code Request}.</p>
<p>For cases where you do need to implement a custom request, this is all you need
to do:</p>
<ul>
<li>Extend the {@code Request&lt;T&gt;} class, where
{@code &lt;T&gt;} represents the type of parsed response
the request expects. So if your parsed response is a string, for example,
create your custom request by extending {@code Request&lt;String&gt;}. See the Volley
toolbox classes {@code StringRequest} and {@code ImageRequest} for examples of
extending {@code Request&lt;T&gt;}.</li>
<li>Implement the abstract methods {@code parseNetworkResponse()}
and {@code deliverResponse()}, described in more detail below.</li>
</ul>
<h3>parseNetworkResponse</h3>
<p>A {@code Response} encapsulates a parsed response for delivery, for a given type
(such as string, image, or JSON). Here is a sample implementation of
{@code parseNetworkResponse()}:</p>
<pre>
&#64;Override
protected Response&lt;T&gt; 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
...
}
</pre>
<p>Note the following:</p>
<ul>
<li>{@code parseNetworkResponse()} takes as its parameter a {@code NetworkResponse}, which
contains the response payload as a byte[], HTTP status code, and response headers.</li>
<li>Your implementation must return a {@code Response&lt;T&gt;}, which contains your typed
response object and cache metadata or an error, such as in the case of a parse failure.</li>
</ul>
<p>If your protocol has non-standard cache semantics, you can build a {@code Cache.Entry}
yourself, but most requests are fine with something like this:
</p>
<pre>return Response.success(myDecodedObject,
HttpHeaderParser.parseCacheHeaders(response));</pre>
<p>
Volley calls {@code parseNetworkResponse()} from a worker thread. This ensures that
expensive parsing operations, such as decoding a JPEG into a Bitmap, don't block the UI
thread.</p>
<h3>deliverResponse</h3>
<p>Volley calls you back on the main thread with the object you returned in
{@code parseNetworkResponse()}. Most requests invoke a callback interface here,
for example:
</p>
<pre>
protected void deliverResponse(T response) {
listener.onResponse(response);
</pre>
<h3>Example: GsonRequest</h3>
<p><a href="http://code.google.com/p/google-gson/">Gson</a> is a library for converting
Java objects to and from JSON using reflection. You can define Java objects that have the
same names as their corresponding JSON keys, pass Gson the class object, and Gson will fill
in the fields for you. Here's a complete implementation of a Volley request that uses
Gson for parsing:</p>
<pre>
public class GsonRequest&lt;T&gt; extends Request&lt;T&gt; {
private final Gson gson = new Gson();
private final Class&lt;T&gt; clazz;
private final Map&lt;String, String&gt; headers;
private final Listener&lt;T&gt; listener;
/**
* Make a GET request and return a parsed object from JSON.
*
* &#64;param url URL of the request to make
* &#64;param clazz Relevant class object, for Gson's reflection
* &#64;param headers Map of request headers
*/
public GsonRequest(String url, Class&lt;T&gt; clazz, Map&lt;String, String&gt; headers,
Listener&lt;T&gt; listener, ErrorListener errorListener) {
super(Method.GET, url, errorListener);
this.clazz = clazz;
this.headers = headers;
this.listener = listener;
}
&#64;Override
public Map&lt;String, String&gt; getHeaders() throws AuthFailureError {
return headers != null ? headers : super.getHeaders();
}
&#64;Override
protected void deliverResponse(T response) {
listener.onResponse(response);
}
&#64;Override
protected Response&lt;T&gt; 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));
}
}
}
</pre>
<p>Volley provides ready-to-use {@code JsonArrayRequest} and {@code JsonArrayObject} classes
if you prefer to take that approach. See <a href="request.html">
Using Standard Request Types</a> for more information.</p>

View File

@ -0,0 +1,281 @@
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}&mdash;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}&mdash;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}&mdash;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>() {
&#64;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>&lt;com.android.volley.toolbox.NetworkImageView
android:id=&quot;&#64;+id/networkImageView&quot;
android:layout_width=&quot;150dp&quot;
android:layout_height=&quot;170dp&quot;
android:layout_centerHorizontal=&quot;true&quot; /&gt;</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&lt;String, Bitmap&gt;
implements ImageCache {
public LruBitmapCache(int maxSize) {
super(maxSize);
}
public LruBitmapCache(Context ctx) {
this(getCacheSize(ctx));
}
&#64;Override
protected int sizeOf(String key, Bitmap value) {
return value.getRowBytes() * value.getHeight();
}
&#64;Override
public Bitmap getBitmap(String url) {
return get(url);
}
&#64;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}&mdash;A request for retrieving a
{@link org.json.JSONArray}
response body at a given URL.</li>
<li>{@code JsonObjectRequest}&mdash;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>() {
&#64;Override
public void onResponse(JSONObject response) {
mTxtDisplay.setText("Response: " + response.toString());
}
}, new Response.ErrorListener() {
&#64;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>.

View File

@ -0,0 +1,204 @@
page.title=Setting Up a RequestQueue
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="#network">Set Up a Network and Cache</a></li>
<li><a href="#singleton">Use a Singleton Pattern</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>The previous lesson showed you how to use the convenience method
<code>Volley.newRequestQueue</code> to set up a {@code RequestQueue}, taking advantage of
Volley's default behaviors. This lesson walks you through the explicit steps of creating a
{@code RequestQueue}, to allow you to supply your own custom behavior.</p>
<p>This lesson also describes the recommended practice of creating a {@code RequestQueue}
as a singleton, which makes the {@code RequestQueue} last the lifetime of your app.</p>
<h2 id="network">Set Up a Network and Cache</h2>
<p>A {@code RequestQueue} needs two things to do its job: a network to perform transport
of the requests, and a cache to handle caching. There are standard implementations of these
available in the Volley toolbox: {@code DiskBasedCache} provides a one-file-per-response
cache with an in-memory index, and {@code BasicNetwork} provides a network transport based
on your choice of {@link android.net.http.AndroidHttpClient} or {@link java.net.HttpURLConnection}.</p>
<p>{@code BasicNetwork} is Volley's default network implementation. A {@code BasicNetwork}
must be initialized with the HTTP client your app is using to connect to the network.
Typically this is {@link android.net.http.AndroidHttpClient} or
{@link java.net.HttpURLConnection}:</p>
<ul>
<li>Use {@link android.net.http.AndroidHttpClient} for apps targeting Android API levels
lower than API Level 9 (Gingerbread). Prior to Gingerbread, {@link java.net.HttpURLConnection}
was unreliable. For more discussion of this topic, see
<a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">
Android's HTTP Clients</a>. </li>
<li>Use {@link java.net.HttpURLConnection} for apps targeting Android API Level 9
(Gingerbread) and higher.</li>
</ul>
<p>To create an app that runs on all versions of Android, you can check the version of
Android the device is running and choose the appropriate HTTP client, for example:</p>
<pre>
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);
</pre>
<p>This snippet shows you the steps involved in setting up a
{@code RequestQueue}:</p>
<pre>
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&lt;String&gt;() {
&#64;Override
public void onResponse(String response) {
// Do something with the response
}
},
new Response.ErrorListener() {
&#64;Override
public void onErrorResponse(VolleyError error) {
// Handle error
}
});
// Add the request to the RequestQueue.
mRequestQueue.add(stringRequest);
...
</pre>
<p>If you just need to make a one-time request and don't want to leave the thread pool
around, you can create the {@code RequestQueue} wherever you need it and call {@code stop()} on the
{@code RequestQueue} once your response or error has come back, using the
{@code Volley.newRequestQueue()} method described in <a href="simple.html">Sending a Simple
Request</a>. But the more common use case is to create the {@code RequestQueue} as a
singleton to keep it running for the lifetime of your app, as described in the next section.</p>
<h2 id="singleton">Use a Singleton Pattern</h2>
<p>If your application makes constant use of the network, it's probably most efficient to
set up a single instance of {@code RequestQueue} that will last the lifetime of your app.
You can achieve this in various ways. The recommended approach is to implement a singleton
class that encapsulates {@code RequestQueue} and other Volley
functionality. Another approach is to subclass {@link android.app.Application} and set up the
{@code RequestQueue} in {@link android.app.Application#onCreate Application.onCreate()}.
But this approach is <a href="{@docRoot}reference/android/app/Application.html">
discouraged</a>; a static singleton can provide the same functionality in a more modular
way. </p>
<p>A key concept is that the {@code RequestQueue} must be instantiated with the
{@link android.app.Application} context, not an {@link android.app.Activity} context. This
ensures that the {@code RequestQueue} will last for the lifetime of your app, instead of
being recreated every time the activity is recreated (for example, when the user
rotates the device).
<p>Here is an example of a singleton class that provides {@code RequestQueue} and
{@code ImageLoader} functionality:</p>
<pre>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&lt;String, Bitmap&gt;
cache = new LruCache&lt;String, Bitmap&gt;(20);
&#64;Override
public Bitmap getBitmap(String url) {
return cache.get(url);
}
&#64;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 &lt;T&gt; void addToRequestQueue(Request&lt;T&gt; req) {
getRequestQueue().add(req);
}
public ImageLoader getImageLoader() {
return mImageLoader;
}
}</pre>
<p>Here are some examples of performing {@code RequestQueue} operations using the singleton
class:</p>
<pre>
// 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);
</pre>

View File

@ -0,0 +1,169 @@
page.title=Sending a Simple 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="#manifest">Add the INTERNET Permission</a></li>
<li><a href="#simple">Use newRequestQueue</a></li>
<li><a href="#send">Send a Request</a></li>
<li><a href="#cancel">Cancel a Request</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>At a high level, you use Volley by creating a {@code RequestQueue} and passing it
{@code Request} objects. The {@code RequestQueue} manages worker threads for running the
network operations, reading from and writing to the cache, and parsing responses. Requests
do the parsing of raw responses and Volley takes care of dispatching the parsed response
back to the main thread for delivery.</p>
<p> This lesson describes how to send a request using the <code>Volley.newRequestQueue</code>
convenience method, which sets up a {@code RequestQueue} for you.
See the next lesson,
<a href="requestqueue.html">Setting Up a RequestQueue</a>, for information on how to set
up a {@code RequestQueue} yourself.</p>
<p>This lesson also describes how to add a request to a {@code RequestQueue} and cancel a
request.</p>
<h2 id="manifest">Add the INTERNET Permission</h2>
<p>To use Volley, you must add the
{@link android.Manifest.permission#INTERNET android.permission.INTERNET} permission
to your app's manifest. Without this, your app won't be able to connect to the network.</p>
<h2 id="simple">Use newRequestQueue</h2>
<p>Volley provides a convenience method <code>Volley.newRequestQueue</code> that sets up a
{@code RequestQueue} for you, using default values, and starts the queue. For example:</p>
<pre>
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<String>() {
&#64;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() {
&#64;Override
public void onErrorResponse(VolleyError error) {
mTextView.setText("That didn't work!");
}
});
// Add the request to the RequestQueue.
queue.add(stringRequest);
</pre>
<p>Volley always delivers parsed responses on the main thread. Running on the main thread
is convenient for populating UI controls with received data, as you can freely modify UI
controls directly from your response handler, but it's especially critical to many of the
important semantics provided by the library, particularly related to canceling requests.
</p>
<p>See <a href="requestqueue.html">Setting Up a RequestQueue</a> for a
description of how to set up a {@code RequestQueue} yourself, instead of using the
<code>Volley.newRequestQueue</code> convenience method.</p>
<h2 id="send">Send a Request</h2>
<p>To send a request, you simply construct one and add it to the {@code RequestQueue} with
{@code add()}, as shown above. Once you add the request it moves through the pipeline,
gets serviced, and has its raw response parsed and delivered.</p>
<p>When you call {@code add()}, Volley runs one cache processing thread and a pool of
network dispatch threads. When you add a request to the queue, it is picked up by the cache
thread and triaged: if the request can be serviced from cache, the cached response is
parsed on the cache thread and the parsed response is delivered on the main thread. If the
request cannot be serviced from cache, it is placed on the network queue. The first
available network thread takes the request from the queue, performs the HTTP transaction,
parsse the response on the worker thread, writes the response to cache, and posts the parsed
response back to the main thread for delivery.</p>
<p>Note that expensive operations like blocking I/O and parsing/decoding are done on worker
threads. You can add a request from any thread, but responses are always delivered on the
main thread.</p>
<p>Figure 1 illustrates the life of a request:</p>
<img src="{@docRoot}images/training/volley-request.png"
alt="system bars">
<p class="img-caption"><strong>Figure 1.</strong> Life of a request.</p>
<h2 id="cancel">Cancel a Request</h2>
<p>To cancel a request, call {@code cancel()} on your {@code Request} object. Once cancelled,
Volley guarantees that your response handler will never be called. What this means in
practice is that you can cancel all of your pending requests in your activity's
{@link android.app.Activity#onStop onStop()} method and you don't have to litter your
response handlers with checks for {@code getActivity() == null},
whether {@code onSaveInstanceState()} has been called already, or other defensive
boilerplate.</p>
<p>To take advantage of this behavior, you would typically have to
track all in-flight requests in order to be able to cancel them at the
appropriate time. There is an easier way: you can associate a tag object with each
request. You can then use this tag to provide a scope of requests to cancel. For
example, you can tag all of your requests with the {@link android.app.Activity} they
are being made on behalf of, and call {@code requestQueue.cancelAll(this)} from
{@link android.app.Activity#onStop onStop()}.
Similarly, you could tag all thumbnail image requests in a
{@link android.support.v4.view.ViewPager} tab with their respective tabs and cancel on swipe
to make sure that the new tab isn't being held up by requests from another one.</p>
<p>Here is an example that uses a string value for the tag:</p>
<ol>
<li>Define your tag and add it to your requests.
<pre>
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);</pre>
</li>
<li>In your activity's {@link android.app.Activity#onStop onStop()} method, cancel all requests that have this tag.
<pre>
&#64;Override
protected void onStop () {
super.onStop();
if (mRequestQueue != null) {
mRequestQueue.cancelAll(TAG);
}
}
</pre></li></ol>
<p>Take care when canceling requests. If you are depending on your response handler to
advance a state or kick off another process, you need to account for this. Again, the
response handler will not be called.
</p>

File diff suppressed because it is too large Load Diff