The previous article introduced the basic uses of the Volley framework, including StringRequest, JsonRequest, ImageRequest, ImageLoader, and more. In this article we implement our own custom Request for a variety of scenarios.
XMLRequest
We know that web data usually comes in two formats, Json and XML. Since We already have JsonRequest in Volley, let’s implement an XMLRequest ourselves.
Let’s look at how StringRequest is implemented:
public class StringRequest extends Request<String> {
/** Lock to guard mListener as it is cleared on cancel() and read on delivery. */
private final Object mLock = new Object();
// @GuardedBy("mLock")
private Listener<String> mListener;
public StringRequest(int method, String url, Listener<String> listener,
ErrorListener errorListener) {
super(method, url, errorListener);
mListener = listener;
}
public StringRequest(String url, Listener<String> listener, ErrorListener errorListener) {
this(Method.GET, url, listener, errorListener);
}
@Override
public void cancel() {
super.cancel();
synchronized (mLock) {
mListener = null;
}
}
@Override
protected void deliverResponse(String response) {
Response.Listener<String> listener;
synchronized (mLock) {
listener = mListener;
}
if(listener ! = null) { listener.onResponse(response); } } @Override protected Response<String> parseNetworkResponse(NetworkResponse response) { String parsed; try { parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers)); } catch (UnsupportedEncodingException e) { parsed = new String(response.data); }returnResponse.success(parsed, HttpHeaderParser.parseCacheHeaders(response)); }}Copy the code
As you can see, StringRequest has very little code and most of the work is done in its parent class.
The basic steps for customizing a Request are:
- Create a callback Listener for a successful response
- Write constructor
- Override the abstract methods in the parent class to parse the data for network request results and successful callback responses.
Here is the code for XMLRequest:
Public class XMLRequest extends Request<XmlPullParser> {private Object mLock = new Object(); // Request a successful callback private Response.Listener<XmlPullParser> Listener; Public XMLRequest(int method, String url, response. Listener<XmlPullParser> Listener, Response.ErrorListener errorListener) { super(method, url, errorListener); this.listener = listener; } // Public XMLRequest(String URL, response. Listener<XmlPullParser> Listener, Response.ErrorListener errorListener) { this(Method.GET, url,listener, errorListener); } @override protected Response<XmlPullParser> parseNetworkResponse(NetworkResponse Response) {try {String xmlString = new String(response.data, HttpHeaderParser.parseCharset(response.headers)); XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); XmlPullParser xmlPullParser = factory.newPullParser(); xmlPullParser.setInput(new StringReader(xmlString));return Response.success(xmlPullParser, HttpHeaderParser.parseCacheHeaders(response));
} catch (UnsupportedEncodingException e) {
return Response.error(new ParseError(e));
} catch (XmlPullParserException e) {
returnResponse.error(new ParseError(e)); }} @override protected void deliverResponse(XmlPullParser response) {synchronized (mLock){synchronized (mLock){ listener.onResponse(response); }} // Override public voidcancel() { super.cancel(); synchronized (mLock){ listener = null; }}}Copy the code
Here we use the Pull method to parse the XML data, using the XmlPullParser class. First, we define a callback Listener object of generic XmlPullParser to call back data that is successfully requested (callback failures are the same, but callback is different depending on the data type returned when the request is successful). The callback is assigned in the constructor, which also mimics StringRequest, where the three-argument constructor calls the four-argument constructor. After inheriting Request, you must override its two abstract methods, parseNetworkResponse() and deliverResponse(). Here’s what they do.
protected Response parseNetworkResponse(NetworkResponse response)
This method is used to parse the response result of a network request and invoke different response methods based on the response result. In XmlRequest, the Response data in Response is first retrieved, parsed into an XmlPullParser format, and then the method that responded successfully is called. If the data fails (unsuccessful request, parsing error, etc.), the method that failed is called.
protected void deliverResponse(T response)
This method is used to call back the data for the successful response. You can see that the parameters of this function already carry the parsed response data of the previous function (for example, StringRequest response data is String and XmlRequest is XmlPullParser). This function calls back the data to the Activity that instantiates the Request for further processing, usually by displaying parsed data on the UI.
The principles behind these two functions and the entire Volley process will be described in later articles.
GsonResquest
In the last implementation of XMLRequest, we’ve already seen the basics of a custom Request. GsonRequest is an open-source JSON data parsing framework that automatically maps a piece of JSON data to an entity class object. Of course, this Request doesn’t actually need to be customized, just add Gson to the StringRequest response result (since only a portion of the Json data is required).
The following is the implementation:
public class GsonRequest<T> extends Request<T> {
private Response.Listener<T> listener;
private Gson mGson;
private Class<T> mClass;
public GsonRequest(int method, String url, Class<T> clazz, Response.Listener<T> listener,
Response.ErrorListener errorListener) {
super(method, url, errorListener);
mGson = new Gson();
this.mClass = clazz;
this.listener = listener;
}
public GsonRequest(String url, Class<T> clazz, Response.Listener<T> listener,
Response.ErrorListener errorListener) {
this(Method.GET, url, clazz, listener, errorListener);
}
@Override
protected Response<T> parseNetworkResponse(NetworkResponse response) {
try {
String jsonString = new String(response.data,
HttpHeaderParser.parseCharset(response.headers));
return Response.success(mGson.fromJson(jsonString,mClass),
HttpHeaderParser.parseCacheHeaders(response));
} catch (UnsupportedEncodingException e) {
returnResponse.error(new ParseError(e)); } } @Override protected void deliverResponse(T response) { listener.onResponse(response); }}Copy the code
One thing to note is that you add a member variable mClass of type Class< T > and assign it in the constructor. This is because the ** mgson.fromjson (jsonString,mClass)** line in the parseNetworkResponse() method needs to explicitly specify the entity class type to be mapped by JSON.
conclusion
This is the end of the custom Request. Most of the content of the article comes from the following blog of Teacher Guo Lin:
Android Volley fully parses (c) and customizes its own Request