1 page.title=Implementing a Custom Request 2 3 trainingnavtop=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://developers.google.com/events/io/sessions/325304728"> 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 27 don't have out-of-the-box Volley support.</p> 28 29 <h2 id="custom-request">Write a Custom Request</h2> 30 31 Most requests have ready-to-use implementations in the toolbox; if your response is a string, 32 image, 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 35 to do:</p> 36 37 <ul> 38 39 <li>Extend the {@code Request<T>} class, where 40 {@code <T>} represents the type of parsed response 41 the request expects. So if your parsed response is a string, for example, 42 create your custom request by extending {@code Request<String>}. See the Volley 43 toolbox classes {@code StringRequest} and {@code ImageRequest} for examples of 44 extending {@code Request<T>}.</li> 45 46 <li>Implement the abstract methods {@code parseNetworkResponse()} 47 and {@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 @Override 59 protected Response<T> 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 76 contains 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 78 response 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} 82 yourself, but most requests are fine with something like this: 83 </p> 84 <pre>return Response.success(myDecodedObject, 85 HttpHeaderParser.parseCacheHeaders(response));</pre> 86 <p> 87 Volley calls {@code parseNetworkResponse()} from a worker thread. This ensures that 88 expensive parsing operations, such as decoding a JPEG into a Bitmap, don't block the UI 89 thread.</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, 95 for example: 96 </p> 97 98 <pre> 99 protected 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 106 Java objects to and from JSON using reflection. You can define Java objects that have the 107 same names as their corresponding JSON keys, pass Gson the class object, and Gson will fill 108 in the fields for you. Here's a complete implementation of a Volley request that uses 109 Gson for parsing:</p> 110 111 <pre> 112 public class GsonRequest<T> extends Request<T> { 113 private final Gson gson = new Gson(); 114 private final Class<T> clazz; 115 private final Map<String, String> headers; 116 private final Listener<T> listener; 117 118 /** 119 * Make a GET request and return a parsed object from JSON. 120 * 121 * @param url URL of the request to make 122 * @param clazz Relevant class object, for Gson's reflection 123 * @param headers Map of request headers 124 */ 125 public GsonRequest(String url, Class<T> clazz, Map<String, String> headers, 126 Listener<T> listener, ErrorListener errorListener) { 127 super(Method.GET, url, errorListener); 128 this.clazz = clazz; 129 this.headers = headers; 130 this.listener = listener; 131 } 132 133 @Override 134 public Map<String, String> getHeaders() throws AuthFailureError { 135 return headers != null ? headers : super.getHeaders(); 136 } 137 138 @Override 139 protected void deliverResponse(T response) { 140 listener.onResponse(response); 141 } 142 143 @Override 144 protected Response<T> 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 162 if you prefer to take that approach. See <a href="request.html"> 163 Using Standard Request Types</a> for more information.</p> 164