1page.title=Implementing a Custom Request
2
3trainingnavtop=true
4
5@jd:body
6
7<div id="tb-wrapper">
8<div id="tb">
9
10<!-- table of contents -->
11<h2>This lesson teaches you to</h2>
12<ol>
13  <li><a href="#custom-request">Write a Custom Request</a></li>
14</ol>
15
16</div>
17</div>
18
19<a class="notice-developers-video wide" href="https://www.youtube.com/watch?v=yhv8l9F44qo">
20<div>
21    <h3>Video</h3>
22    <p>Volley: Easy, Fast Networking for Android</p>
23</div>
24</a>
25
26<p>This lesson describes how to implement your own custom request types, for types that
27don't have out-of-the-box Volley support.</p>
28
29<h2 id="custom-request">Write a Custom Request</h2>
30
31Most requests have ready-to-use implementations in the toolbox; if your response is a string,
32image, or JSON, you probably won't need to implement a custom {@code Request}.</p>
33
34<p>For cases where you do need to implement a custom request, this is all you need
35to do:</p>
36
37<ul>
38
39<li>Extend the {@code Request<T>} class, where
40{@code <T>} represents the type of parsed response
41the request expects. So if your parsed response is a string, for example,
42create your custom request by extending {@code Request<String>}. See the Volley
43toolbox classes {@code StringRequest} and {@code ImageRequest} for examples of
44extending {@code Request<T>}.</li>
45
46<li>Implement the abstract methods {@code parseNetworkResponse()}
47and {@code deliverResponse()}, described in more detail below.</li>
48
49</ul>
50
51<h3>parseNetworkResponse</h3>
52
53<p>A {@code Response} encapsulates a parsed response for delivery, for a given type
54(such as string, image, or JSON). Here is a sample implementation of
55{@code parseNetworkResponse()}:</p>
56
57<pre>
58&#64;Override
59protected Response&lt;T&gt; parseNetworkResponse(
60        NetworkResponse response) {
61    try {
62        String json = new String(response.data,
63        HttpHeaderParser.parseCharset(response.headers));
64    return Response.success(gson.fromJson(json, clazz),
65    HttpHeaderParser.parseCacheHeaders(response));
66    }
67    // handle errors
68...
69}
70</pre>
71
72<p>Note the following:</p>
73
74<ul>
75<li>{@code parseNetworkResponse()} takes as its parameter a {@code NetworkResponse}, which
76contains the response payload as a byte[], HTTP status code, and response headers.</li>
77<li>Your implementation must return a {@code Response<T>}, which contains your typed
78response object and cache metadata or an error, such as in the case of a parse failure.</li>
79</ul>
80
81<p>If your protocol has non-standard cache semantics, you can build a {@code Cache.Entry}
82yourself, but most requests are fine with something like this:
83</p>
84<pre>return Response.success(myDecodedObject,
85        HttpHeaderParser.parseCacheHeaders(response));</pre>
86<p>
87Volley calls {@code parseNetworkResponse()} from a worker thread. This ensures that
88expensive parsing operations, such as decoding a JPEG into a Bitmap, don't block the UI
89thread.</p>
90
91<h3>deliverResponse</h3>
92
93<p>Volley calls you back on the main thread with the object you returned in
94{@code parseNetworkResponse()}. Most requests invoke a callback interface here,
95for example:
96</p>
97
98<pre>
99protected void deliverResponse(T response) {
100        listener.onResponse(response);
101</pre>
102
103<h3>Example: GsonRequest</h3>
104
105<p><a href="http://code.google.com/p/google-gson/">Gson</a> is a library for converting
106Java objects to and from JSON using reflection. You can define Java objects that have the
107same names as their corresponding JSON keys, pass Gson the class object, and Gson will fill
108in the fields for you. Here's a complete implementation of a Volley request that uses
109Gson for parsing:</p>
110
111<pre>
112public class GsonRequest&lt;T&gt; extends Request&lt;T&gt; {
113    private final Gson gson = new Gson();
114    private final Class&lt;T&gt; clazz;
115    private final Map&lt;String, String&gt; headers;
116    private final Listener&lt;T&gt; listener;
117
118    /**
119     * Make a GET request and return a parsed object from JSON.
120     *
121     * &#64;param url URL of the request to make
122     * &#64;param clazz Relevant class object, for Gson's reflection
123     * &#64;param headers Map of request headers
124     */
125    public GsonRequest(String url, Class&lt;T&gt; clazz, Map&lt;String, String&gt; headers,
126            Listener&lt;T&gt; listener, ErrorListener errorListener) {
127        super(Method.GET, url, errorListener);
128        this.clazz = clazz;
129        this.headers = headers;
130        this.listener = listener;
131    }
132
133    &#64;Override
134    public Map&lt;String, String&gt; getHeaders() throws AuthFailureError {
135        return headers != null ? headers : super.getHeaders();
136    }
137
138    &#64;Override
139    protected void deliverResponse(T response) {
140        listener.onResponse(response);
141    }
142
143    &#64;Override
144    protected Response&lt;T&gt; parseNetworkResponse(NetworkResponse response) {
145        try {
146            String json = new String(
147                    response.data,
148                    HttpHeaderParser.parseCharset(response.headers));
149            return Response.success(
150                    gson.fromJson(json, clazz),
151                    HttpHeaderParser.parseCacheHeaders(response));
152        } catch (UnsupportedEncodingException e) {
153            return Response.error(new ParseError(e));
154        } catch (JsonSyntaxException e) {
155            return Response.error(new ParseError(e));
156        }
157    }
158}
159</pre>
160
161<p>Volley provides ready-to-use {@code JsonArrayRequest} and {@code JsonArrayObject} classes
162if you prefer to take that approach. See <a href="request.html">
163Using Standard Request Types</a> for more information.</p>
164