* commit 'ea5fa98c7c381a37c113b7d2efdd6a406d902949': Doc update: new Volley class
This commit is contained in:
19
\
Normal file
19
\
Normal 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
|
||||||
|
#
|
BIN
docs/html/images/training/volley-request.png
Normal file
BIN
docs/html/images/training/volley-request.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 60 KiB |
@ -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>
|
||||||
|
@ -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>
|
||||||
|
@ -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>
|
||||||
|
133
docs/html/training/volley/index.jd
Normal file
133
docs/html/training/volley/index.jd
Normal 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>
|
163
docs/html/training/volley/request-custom.jd
Normal file
163
docs/html/training/volley/request-custom.jd
Normal 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<T>} class, where
|
||||||
|
{@code <T>} 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<String>}. See the Volley
|
||||||
|
toolbox classes {@code StringRequest} and {@code ImageRequest} for examples of
|
||||||
|
extending {@code Request<T>}.</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>
|
||||||
|
@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
|
||||||
|
...
|
||||||
|
}
|
||||||
|
</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<T>}, 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<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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</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>
|
281
docs/html/training/volley/request.jd
Normal file
281
docs/html/training/volley/request.jd
Normal 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}—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>.
|
204
docs/html/training/volley/requestqueue.jd
Normal file
204
docs/html/training/volley/requestqueue.jd
Normal 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<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);
|
||||||
|
...
|
||||||
|
</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<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;
|
||||||
|
}
|
||||||
|
}</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>
|
169
docs/html/training/volley/simple.jd
Normal file
169
docs/html/training/volley/simple.jd
Normal 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>() {
|
||||||
|
@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);
|
||||||
|
</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>
|
||||||
|
@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>
|
2259
docs/image_sources/training/volley/volley-request.graffle
Normal file
2259
docs/image_sources/training/volley/volley-request.graffle
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user