详细解读Volley(四)—— 自定义Request
Volley中提供了几个Request,如果我们有特殊的需求,完全可以自定义Request的,自定义Request自然要继承Request,那么本篇就教大家来一步一步地定义一个自己的Request类。
一、继承Request
如果我们的request的对象不是string,也不是JsonObject,而是一个奇怪的对象呢?我这里建立了一个类,叫做:Kale,然后定义了一个CustomReqeust去继承Reqeust,得到如下的代码。
package com.kale.volleytest; import com.android.volley.NetworkResponse; import com.android.volley.Request; import com.android.volley.Response; import com.android.volley.Response.ErrorListener; import com.android.volley.Response.Listener; public class CustomReqeust extends Request<Kale>{ public CustomReqeust(int method, String url, ErrorListener listener) { super(method, url, listener); } @Override protected Response<Kale> parseNetworkResponse(NetworkResponse response) { // TODO 自动生成的方法存根 return null; } @Override protected void deliverResponse(Kale response) { // TODO 自动生成的方法存根 } }
分析:
public CustomReqeust(int method, String url, ErrorListener listener)
构造函数中调用了父类的方法,初始化了当前对象。传入三个参数:①请求方式,即POST/GET,②请求的URL,③出错时的回调监听器
protected Response<Kale> parseNetworkResponse(NetworkResponse response)
解析网络响应的结果,从NetworkResponse的代码中我们就可以知道它里面有什么东西了。
/** * Data and headers returned from {@link Network#performRequest(Request)}. */ public class NetworkResponse { /** * Creates a new network response. * @param statusCode the HTTP status code * @param data Response body * @param headers Headers returned with this response, or null for none * @param notModified True if the server returned a 304 and the data was already in cache * @param networkTimeMs Round-trip network time to receive network response */ public NetworkResponse(int statusCode, byte[] data, Map<String, String> headers, boolean notModified, long networkTimeMs)
响应码啊,请求头什么的,最最主要的就是这个比特数组的data,响应的结果就在里面。我们可以自由的进行处理了~
protected void deliverResponse(Kale response)
分发响应的结果,我们可以通过将这个response放到监听器里来获取响应结果。
二、分析StringRequest
我们现在已经对request的子类有了基本的认识,现在就来看看StringRequest的源码吧,别担心,很短!
package com.android.volley.toolbox;public class StringRequest extends Request<String> { // 建立监听器来获得响应成功时返回的结果 private final Listener<String> mListener; // 传入请求方法,url,成功时的监听器,失败时的监听器 public StringRequest(int method, String url, Listener<String> listener, ErrorListener errorListener) { super(method, url, errorListener); // 初始化成功时的监听器 mListener = listener; } /** * Creates a new GET request. * 建立一个默认的GET请求,调用了上面的构造函数 */ public StringRequest(String url, Listener<String> listener, ErrorListener errorListener) { this(Method.GET, url, listener, errorListener); } @Override protected void deliverResponse(String response) { // 用监听器的方法来传递下响应的结果 mListener.onResponse(response); } @Override protected Response<String> parseNetworkResponse(NetworkResponse response) { String parsed; try { // 调用了new String(byte[] data, String charsetName) 这个构造函数来构建String对象, // 将byte数组按照特定的编码方式转换为String对象 // 主要部分是data parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers)); } catch (UnsupportedEncodingException e) { parsed = new String(response.data); } return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response)); } }
分析完代码我们应该就能知道改如何自定义Request了,其实没啥高深的东西。
三、自定义XMLRequest
代码来自:http://blog.csdn.net/guolin_blog/article/details/17612763
public class XMLRequest extends Request<XmlPullParser> { private final Listener<XmlPullParser> mListener; public XMLRequest(int method, String url, Listener<XmlPullParser> listener, ErrorListener errorListener) { super(method, url, errorListener); mListener = listener; } public XMLRequest(String url, Listener<XmlPullParser> listener, 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) { return Response.error(new ParseError(e)); } } @Override protected void deliverResponse(XmlPullParser response) { mListener.onResponse(response); } }
这里用到了XmlPull的知识,如果不是很了解,可以去这篇文章看看:http://www.cnblogs.com/tianzhijiexian/p/4020250.html
测试代码:
XMLRequest xmlRequest = new XMLRequest( "http://flash.weather.com.cn/wmaps/xml/china.xml", new Response.Listener<XmlPullParser>() { @Override public void onResponse(XmlPullParser response) { try { int eventType = response.getEventType(); while (eventType != XmlPullParser.END_DOCUMENT) { switch (eventType) { case XmlPullParser.START_TAG: String nodeName = response.getName(); if ("city".equals(nodeName)) { String pName = response.getAttributeValue(0); Log.d("TAG", "pName is " + pName); } break; } eventType = response.next(); } } catch (XmlPullParserException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { Log.e("TAG", error.getMessage(), error); } }); mQueue.add(xmlRequest);
结果:
四、自定义GsonRequest
代码来自:http://blog.csdn.net/guolin_blog/article/details/17612763
public class GsonRequest<T> extends Request<T> { private final Listener<T> mListener; private Gson mGson; private Class<T> mClass; public GsonRequest(int method, String url, Class<T> clazz, Listener<T> listener, ErrorListener errorListener) { super(method, url, errorListener); mGson = new Gson(); mClass = clazz; mListener = listener; } public GsonRequest(String url, Class<T> clazz, Listener<T> listener, 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) { return Response.error(new ParseError(e)); } } @Override protected void deliverResponse(T response) { mListener.onResponse(response); } }
代码十分简单,先是将服务器响应的数据解析出来,然后通过调用Gson的fromJson方法将数据组装成对象。在deliverResponse方法中仍然是将最终的数据进行回调。
用法:
建立一个对象类,比如这里的weather、WeatherInfo类,然后初始化GsonRequest对象,最后把GsonRequest对象添加到队列中。
Weather:

public class Weather { private WeatherInfo weatherinfo; public WeatherInfo getWeatherinfo() { return weatherinfo; } public void setWeatherinfo(WeatherInfo weatherinfo) { this.weatherinfo = weatherinfo; } }
WeatherInfo:

public class WeatherInfo { private String city; private String temp; private String time; public String getCity() { return city; } public void setCity(String city) { this.city = city; } public String getTemp() { return temp; } public void setTemp(String temp) { this.temp = temp; } public String getTime() { return time; } public void setTime(String time) { this.time = time; } }
Java测试代码:
GsonRequest<Weather> gsonRequest = new GsonRequest<Weather>( "http://www.weather.com.cn/data/sk/101010100.html", Weather.class, new Response.Listener<Weather>() { @Override public void onResponse(Weather weather) { WeatherInfo weatherInfo = weather.getWeatherinfo(); Log.d("TAG", "city is " + weatherInfo.getCity()); Log.d("TAG", "temp is " + weatherInfo.getTemp()); Log.d("TAG", "time is " + weatherInfo.getTime()); } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { Log.e("TAG", error.getMessage(), error); } }); mQueue.add(gsonRequest);
五、重写getBody()方法来添加post参数
我们可以在JsonRequest类中发现如下代码:
/** * Returns the raw POST or PUT body to be sent. * * @throws AuthFailureError in the event of auth failure */ @Override public byte[] getBody() { try { return mRequestBody == null ? null : mRequestBody.getBytes(PROTOCOL_CHARSET); } catch (UnsupportedEncodingException uee) { VolleyLog.wtf("Unsupported Encoding while trying to get the bytes of %s using %s", mRequestBody, PROTOCOL_CHARSET); return null; } }
不用看代码,直接看注释,说明这里执行post请求,所以我们可以在这里设置post参数。这里
return mRequestBody == null ? null : mRequestBody.getBytes(PROTOCOL_CHARSET);
返回的就是post参数了。
如果我们想要传递POST数据,可以参考上面的代码,重写Request的getBody()方法,放入自己的参数,举例如下:
/** http请求编码方式 */ private static final String PROTOCOL_CHARSET = "utf-8"; private String mUserName;
@Override public byte[] getBody() { try { return mUserName == null ? null : mUserName.getBytes(PROTOCOL_CHARSET); } catch (UnsupportedEncodingException uee) { VolleyLog.wtf("Unsupported Encoding while trying to get the bytes of %s using %s", mUserName, PROTOCOL_CHARSET); return null; } }
完整代码(来自:http://blog.csdn.net/ttdevs/article/details/17586205):

public class CustomReqeust extends Request<String> { /** http请求编码方式 */ private static final String PROTOCOL_CHARSET = "utf-8"; private Listener<String> mListener; private String mUserName; public CustomReqeust(String url, String userName, Listener<String> listener, ErrorListener errorListener) { super(Method.POST, url, errorListener); mUserName = userName; mListener = listener; } @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); } return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response)); } @Override protected void deliverResponse(String response) { mListener.onResponse(response); } @Override public byte[] getBody() { try { return mUserName == null ? null : mUserName.getBytes(PROTOCOL_CHARSET); } catch (UnsupportedEncodingException uee) { VolleyLog.wtf("Unsupported Encoding while trying to get the bytes of %s using %s", mUserName, PROTOCOL_CHARSET); return null; } } }
测试代码:
private void customRequest() { CustomReqeust request = new CustomReqeust(URL, "CustomVolley", new Listener<String>() { @Override public void onResponse(String arg0) { Toast.makeText(getApplicationContext(), arg0, Toast.LENGTH_LONG).show(); Log.d("onResponse", arg0); } }, new ErrorListener() { @Override public void onErrorResponse(VolleyError arg0) { Toast.makeText(getApplicationContext(), arg0.toString(), Toast.LENGTH_LONG).show(); Log.d("onErrorResponse", arg0.toString()); } }); mQueue.add(request); }
抓包结果:
得到了传递的username = CustomVolley
参考自:
http://blog.csdn.net/t12x3456/article/details/9221611
http://blog.csdn.net/guolin_blog/article/details/17612763
http://blog.csdn.net/ttdevs/article/details/17586205
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?