Android Volley完全解析(三),定制自己的Request

来源:互联网 发布:浙江软件行业协会 编辑:程序博客网 时间:2024/06/07 06:30

转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/17612763


经过前面两篇文章的学习,我们已经掌握了Volley各种Request的使用方法,包括StringRequest、JsonRequest、ImageRequest等。其中StringRequest用于请求一条普通的文本数据,JsonRequest(JsonObjectRequest、JsonArrayRequest)用于请求一条JSON格式的数据,ImageRequest则是用于请求网络上的一张图片。


可是Volley提供给我们的Request类型就只有这么多,而我们都知道,在网络上传输的数据通常有两种格式,JSON和XML,那么如果想要请求一条XML格式的数据该怎么办呢?其实很简单,Volley提供了非常强的扩展机制,使得我们可以很轻松地定制出任意类型的Request,这也就是本篇文章的主题了。


在开始之前还是友情提醒一下,如果你还没有阅读过我前面两篇关于Volley的文章,建议先去阅读一下Android Volley完全解析(一),初识Volley的基本用法Android Volley完全解析(二),使用Volley加载网络图片


1. 自定义XMLRequest


下面我们准备自定义一个XMLRequest,用于请求一条XML格式的数据。那么该从哪里开始入手呢?额,好像是有些无从下手。遇到这种情况,我们应该去参考一下Volley的源码,看一看StringRequest是怎么实现的,然后就可以模仿着写出XMLRequest了。首先看下StringRequest的源码,如下所示:

[java] view plain copy
print?
  1. /** 
  2.  * A canned request for retrieving the response body at a given URL as a String. 
  3.  */  
  4. public class StringRequest extends Request<String> {  
  5.     private final Listener<String> mListener;  
  6.   
  7.     /** 
  8.      * Creates a new request with the given method. 
  9.      * 
  10.      * @param method the request {@link Method} to use 
  11.      * @param url URL to fetch the string at 
  12.      * @param listener Listener to receive the String response 
  13.      * @param errorListener Error listener, or null to ignore errors 
  14.      */  
  15.     public StringRequest(int method, String url, Listener<String> listener,  
  16.             ErrorListener errorListener) {  
  17.         super(method, url, errorListener);  
  18.         mListener = listener;  
  19.     }  
  20.   
  21.     /** 
  22.      * Creates a new GET request. 
  23.      * 
  24.      * @param url URL to fetch the string at 
  25.      * @param listener Listener to receive the String response 
  26.      * @param errorListener Error listener, or null to ignore errors 
  27.      */  
  28.     public StringRequest(String url, Listener<String> listener, ErrorListener errorListener) {  
  29.         this(Method.GET, url, listener, errorListener);  
  30.     }  
  31.   
  32.     @Override  
  33.     protected void deliverResponse(String response) {  
  34.         mListener.onResponse(response);  
  35.     }  
  36.   
  37.     @Override  
  38.     protected Response<String> parseNetworkResponse(NetworkResponse response) {  
  39.         String parsed;  
  40.         try {  
  41.             parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers));  
  42.         } catch (UnsupportedEncodingException e) {  
  43.             parsed = new String(response.data);  
  44.         }  
  45.         return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response));  
  46.     }  
  47. }  
/** * A canned request for retrieving the response body at a given URL as a String. */public class StringRequest extends Request<String> {    private final Listener<String> mListener;    /**     * Creates a new request with the given method.     *     * @param method the request {@link Method} to use     * @param url URL to fetch the string at     * @param listener Listener to receive the String response     * @param errorListener Error listener, or null to ignore errors     */    public StringRequest(int method, String url, Listener<String> listener,            ErrorListener errorListener) {        super(method, url, errorListener);        mListener = listener;    }    /**     * Creates a new GET request.     *     * @param url URL to fetch the string at     * @param listener Listener to receive the String response     * @param errorListener Error listener, or null to ignore errors     */    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 {            parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers));        } catch (UnsupportedEncodingException e) {            parsed = new String(response.data);        }        return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response));    }}

可以看到,StringRequest的源码很简练,根本就没几行代码,我们一起来分析下。首先StringRequest是继承自Request类的,Request可以指定一个泛型类,这里指定的当然就是String了,接下来StringRequest中提供了两个有参的构造函数,参数包括请求类型,请求地址,以及响应回调等,由于我们已经很熟悉StringRequest的用法了,相信这几个参数的作用都不用再解释了吧。但需要注意的是,在构造函数中一定要调用super()方法将这几个参数传给父类,因为HTTP的请求和响应都是在父类中自动处理的。


另外,由于Request类中的deliverResponse()和parseNetworkResponse()是两个抽象方法,因此StringRequest中需要对这两个方法进行实现。deliverResponse()方法中的实现很简单,仅仅是调用了mListener中的onResponse()方法,并将response内容传入即可,这样就可以将服务器响应的数据进行回调了。parseNetworkResponse()方法中则应该对服务器响应的数据进行解析,其中数据是以字节的形式存放在NetworkResponse的data变量中的,这里将数据取出然后组装成一个String,并传入Response的success()方法中即可。


了解了StringRequest的实现原理,下面我们就可以动手来尝试实现一下XMLRequest了,代码如下所示:

[java] view plain copy
print?
  1. public class XMLRequest extends Request<XmlPullParser> {  
  2.   
  3.     private final Listener<XmlPullParser> mListener;  
  4.   
  5.     public XMLRequest(int method, String url, Listener<XmlPullParser> listener,  
  6.             ErrorListener errorListener) {  
  7.         super(method, url, errorListener);  
  8.         mListener = listener;  
  9.     }  
  10.   
  11.     public XMLRequest(String url, Listener<XmlPullParser> listener, ErrorListener errorListener) {  
  12.         this(Method.GET, url, listener, errorListener);  
  13.     }  
  14.   
  15.     @Override  
  16.     protected Response<XmlPullParser> parseNetworkResponse(NetworkResponse response) {  
  17.         try {  
  18.             String xmlString = new String(response.data,  
  19.                     HttpHeaderParser.parseCharset(response.headers));  
  20.             XmlPullParserFactory factory = XmlPullParserFactory.newInstance();  
  21.             XmlPullParser xmlPullParser = factory.newPullParser();  
  22.             xmlPullParser.setInput(new StringReader(xmlString));  
  23.             return Response.success(xmlPullParser, HttpHeaderParser.parseCacheHeaders(response));  
  24.         } catch (UnsupportedEncodingException e) {  
  25.             return Response.error(new ParseError(e));  
  26.         } catch (XmlPullParserException e) {  
  27.             return Response.error(new ParseError(e));  
  28.         }  
  29.     }  
  30.   
  31.     @Override  
  32.     protected void deliverResponse(XmlPullParser response) {  
  33.         mListener.onResponse(response);  
  34.     }  
  35.   
  36. }  
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);    }}

可以看到,其实并没有什么太多的逻辑,基本都是仿照StringRequest写下来的,XMLRequest也是继承自Request类的,只不过这里指定的泛型类是XmlPullParser,说明我们准备使用Pull解析的方式来解析XML。在parseNetworkResponse()方法中,先是将服务器响应的数据解析成一个字符串,然后设置到XmlPullParser对象中,在deliverResponse()方法中则是将XmlPullParser对象进行回调。


好了,就是这么简单,下面我们尝试使用这个XMLRequest来请求一段XML格式的数据。http://flash.weather.com.cn/wmaps/xml/china.xml这个接口会将中国所有的省份数据以XML格式进行返回,如下所示:

[html] view plain copy
print?
  1. <china dn=“day” slick-uniqueid=“3”>  
  2. <city quName=“黑龙江” pyName=“heilongjiang” cityname=“哈尔滨” state1=“0” state2=“0” stateDetailed=“晴” tem1=“18” tem2=“6” windState=“西北风3-4级转西风小于3级”/>  
  3. <city quName=“吉林” pyName=“jilin” cityname=“长春” state1=“0” state2=“0” stateDetailed=“晴” tem1=“19” tem2=“6” windState=“西北风3-4级转小于3级”/>  
  4. <city quName=“辽宁” pyName=“liaoning” cityname=“沈阳” state1=“0” state2=“0” stateDetailed=“晴” tem1=“21” tem2=“7” windState=“东北风3-4级”/>  
  5. <city quName=“海南” pyName=“hainan” cityname=“海口” state1=“1” state2=“1” stateDetailed=“多云” tem1=“30” tem2=“24” windState=“微风”/>  
  6. <city quName=“内蒙古” pyName=“neimenggu” cityname=“呼和浩特” state1=“0” state2=“0” stateDetailed=“晴” tem1=“19” tem2=“5” windState=“东风3-4级”/>  
  7. <city quName=“新疆” pyName=“xinjiang” cityname=“乌鲁木齐” state1=“0” state2=“0” stateDetailed=“晴” tem1=“22” tem2=“10” windState=“微风转东南风小于3级”/>  
  8. <city quName=“西藏” pyName=“xizang” cityname=“拉萨” state1=“1” state2=“7” stateDetailed=“多云转小雨” tem1=“18” tem2=“4” windState=“微风”/>  
  9. <city quName=“青海” pyName=“qinghai” cityname=“西宁” state1=“0” state2=“1” stateDetailed=“晴转多云” tem1=“18” tem2=“2” windState=“微风”/>  
  10. <city quName=“宁夏” pyName=“ningxia” cityname=“银川” state1=“0” state2=“0” stateDetailed=“晴” tem1=“19” tem2=“8” windState=“微风”/>  
  11. <city quName=“甘肃” pyName=“gansu” cityname=“兰州” state1=“0” state2=“0” stateDetailed=“晴” tem1=“21” tem2=“6” windState=“微风”/>  
  12. <city quName=“河北” pyName=“hebei” cityname=“石家庄” state1=“0” state2=“0” stateDetailed=“晴” tem1=“25” tem2=“12” windState=“北风小于3级”/>  
  13. <city quName=“河南” pyName=“henan” cityname=“郑州” state1=“0” state2=“0” stateDetailed=“晴” tem1=“24” tem2=“13” windState=“微风”/>  
  14. <city quName=“湖北” pyName=“hubei” cityname=“武汉” state1=“0” state2=“0” stateDetailed=“晴” tem1=“24” tem2=“12” windState=“微风”/>  
  15. <city quName=“湖南” pyName=“hunan” cityname=“长沙” state1=“2” state2=“1” stateDetailed=“阴转多云” tem1=“20” tem2=“15” windState=“北风小于3级”/>  
  16. <city quName=“山东” pyName=“shandong” cityname=“济南” state1=“1” state2=“1” stateDetailed=“多云” tem1=“20” tem2=“10” windState=“北风3-4级转小于3级”/>  
  17. <city quName=“江苏” pyName=“jiangsu” cityname=“南京” state1=“2” state2=“2” stateDetailed=“阴” tem1=“19” tem2=“13” windState=“西北风4-5级转3-4级”/>  
  18. <city quName=“安徽” pyName=“anhui” cityname=“合肥” state1=“2” state2=“1” stateDetailed=“阴转多云” tem1=“20” tem2=“12” windState=“西北风转北风3-4级”/>  
  19. <city quName=“山西” pyName=“shanxi” cityname=“太原” state1=“0” state2=“0” stateDetailed=“晴” tem1=“22” tem2=“8” windState=“微风”/>  
  20. <city quName=“陕西” pyName=“sanxi” cityname=“西安” state1=“1” state2=“0” stateDetailed=“多云转晴” tem1=“21” tem2=“9” windState=“东北风小于3级”/>  
  21. <city quName=“四川” pyName=“sichuan” cityname=“成都” state1=“1” state2=“1” stateDetailed=“多云” tem1=“26” tem2=“15” windState=“南风小于3级”/>  
  22. <city quName=“云南” pyName=“yunnan” cityname=“昆明” state1=“7” state2=“7” stateDetailed=“小雨” tem1=“21” tem2=“13” windState=“微风”/>  
  23. <city quName=“贵州” pyName=“guizhou” cityname=“贵阳” state1=“1” state2=“3” stateDetailed=“多云转阵雨” tem1=“21” tem2=“11” windState=“东风小于3级”/>  
  24. <city quName=“浙江” pyName=“zhejiang” cityname=“杭州” state1=“3” state2=“1” stateDetailed=“阵雨转多云” tem1=“22” tem2=“14” windState=“微风”/>  
  25. <city quName=“福建” pyName=“fujian” cityname=“福州” state1=“1” state2=“2” stateDetailed=“多云转阴” tem1=“28” tem2=“18” windState=“微风”/>  
  26. <city quName=“江西” pyName=“jiangxi” cityname=“南昌” state1=“2” state2=“1” stateDetailed=“阴转多云” tem1=“23” tem2=“15” windState=“北风3-4级转微风”/>  
  27. <city quName=“广东” pyName=“guangdong” cityname=“广州” state1=“3” state2=“2” stateDetailed=“阵雨转阴” tem1=“26” tem2=“20” windState=“微风”/>  
  28. <city quName=“广西” pyName=“guangxi” cityname=“南宁” state1=“3” state2=“3” stateDetailed=“阵雨” tem1=“23” tem2=“19” windState=“东北风小于3级”/>  
  29. <city quName=“北京” pyName=“beijing” cityname=“北京” state1=“0” state2=“0” stateDetailed=“晴” tem1=“26” tem2=“10” windState=“微风”/>  
  30. <city quName=“天津” pyName=“tianjin” cityname=“天津” state1=“1” state2=“0” stateDetailed=“多云转晴” tem1=“22” tem2=“13” windState=“东北风3-4级转小于3级”/>  
  31. <city quName=“上海” pyName=“shanghai” cityname=“上海” state1=“7” state2=“1” stateDetailed=“小雨转多云” tem1=“20” tem2=“16” windState=“西北风3-4级”/>  
  32. <city quName=“重庆” pyName=“chongqing” cityname=“重庆” state1=“1” state2=“3” stateDetailed=“多云转阵雨” tem1=“21” tem2=“14” windState=“微风”/>  
  33. <city quName=“香港” pyName=“xianggang” cityname=“香港” state1=“3” state2=“1” stateDetailed=“阵雨转多云” tem1=“26” tem2=“22” windState=“微风”/>  
  34. <city quName=“澳门” pyName=“aomen” cityname=“澳门” state1=“3” state2=“1” stateDetailed=“阵雨转多云” tem1=“27” tem2=“22” windState=“东北风3-4级转微风”/>  
  35. <city quName=“台湾” pyName=“taiwan” cityname=“台北” state1=“9” state2=“7” stateDetailed=“大雨转小雨” tem1=“28” tem2=“21” windState=“微风”/>  
  36. <city quName=“西沙” pyName=“xisha” cityname=“西沙” state1=“3” state2=“3” stateDetailed=“阵雨” tem1=“30” tem2=“26” windState=“东北风4-5级”/>  
  37. <city quName=“南沙” pyName=“nanshadao” cityname=“南沙” state1=“1” state2=“1” stateDetailed=“多云” tem1=“32” tem2=“27” windState=“东风4-5级”/>  
  38. <city quName=“钓鱼岛” pyName=“diaoyudao” cityname=“钓鱼岛” state1=“7” state2=“1” stateDetailed=“小雨转多云” tem1=“23” tem2=“19” windState=“西南风3-4级转北风5-6级”/>  
  39. </china>  
<china dn="day" slick-uniqueid="3"><city quName="黑龙江" pyName="heilongjiang" cityname="哈尔滨" state1="0" state2="0" stateDetailed="晴" tem1="18" tem2="6" windState="西北风3-4级转西风小于3级"/><city quName="吉林" pyName="jilin" cityname="长春" state1="0" state2="0" stateDetailed="晴" tem1="19" tem2="6" windState="西北风3-4级转小于3级"/><city quName="辽宁" pyName="liaoning" cityname="沈阳" state1="0" state2="0" stateDetailed="晴" tem1="21" tem2="7" windState="东北风3-4级"/><city quName="海南" pyName="hainan" cityname="海口" state1="1" state2="1" stateDetailed="多云" tem1="30" tem2="24" windState="微风"/><city quName="内蒙古" pyName="neimenggu" cityname="呼和浩特" state1="0" state2="0" stateDetailed="晴" tem1="19" tem2="5" windState="东风3-4级"/><city quName="新疆" pyName="xinjiang" cityname="乌鲁木齐" state1="0" state2="0" stateDetailed="晴" tem1="22" tem2="10" windState="微风转东南风小于3级"/><city quName="西藏" pyName="xizang" cityname="拉萨" state1="1" state2="7" stateDetailed="多云转小雨" tem1="18" tem2="4" windState="微风"/><city quName="青海" pyName="qinghai" cityname="西宁" state1="0" state2="1" stateDetailed="晴转多云" tem1="18" tem2="2" windState="微风"/><city quName="宁夏" pyName="ningxia" cityname="银川" state1="0" state2="0" stateDetailed="晴" tem1="19" tem2="8" windState="微风"/><city quName="甘肃" pyName="gansu" cityname="兰州" state1="0" state2="0" stateDetailed="晴" tem1="21" tem2="6" windState="微风"/><city quName="河北" pyName="hebei" cityname="石家庄" state1="0" state2="0" stateDetailed="晴" tem1="25" tem2="12" windState="北风小于3级"/><city quName="河南" pyName="henan" cityname="郑州" state1="0" state2="0" stateDetailed="晴" tem1="24" tem2="13" windState="微风"/><city quName="湖北" pyName="hubei" cityname="武汉" state1="0" state2="0" stateDetailed="晴" tem1="24" tem2="12" windState="微风"/><city quName="湖南" pyName="hunan" cityname="长沙" state1="2" state2="1" stateDetailed="阴转多云" tem1="20" tem2="15" windState="北风小于3级"/><city quName="山东" pyName="shandong" cityname="济南" state1="1" state2="1" stateDetailed="多云" tem1="20" tem2="10" windState="北风3-4级转小于3级"/><city quName="江苏" pyName="jiangsu" cityname="南京" state1="2" state2="2" stateDetailed="阴" tem1="19" tem2="13" windState="西北风4-5级转3-4级"/><city quName="安徽" pyName="anhui" cityname="合肥" state1="2" state2="1" stateDetailed="阴转多云" tem1="20" tem2="12" windState="西北风转北风3-4级"/><city quName="山西" pyName="shanxi" cityname="太原" state1="0" state2="0" stateDetailed="晴" tem1="22" tem2="8" windState="微风"/><city quName="陕西" pyName="sanxi" cityname="西安" state1="1" state2="0" stateDetailed="多云转晴" tem1="21" tem2="9" windState="东北风小于3级"/><city quName="四川" pyName="sichuan" cityname="成都" state1="1" state2="1" stateDetailed="多云" tem1="26" tem2="15" windState="南风小于3级"/><city quName="云南" pyName="yunnan" cityname="昆明" state1="7" state2="7" stateDetailed="小雨" tem1="21" tem2="13" windState="微风"/><city quName="贵州" pyName="guizhou" cityname="贵阳" state1="1" state2="3" stateDetailed="多云转阵雨" tem1="21" tem2="11" windState="东风小于3级"/><city quName="浙江" pyName="zhejiang" cityname="杭州" state1="3" state2="1" stateDetailed="阵雨转多云" tem1="22" tem2="14" windState="微风"/><city quName="福建" pyName="fujian" cityname="福州" state1="1" state2="2" stateDetailed="多云转阴" tem1="28" tem2="18" windState="微风"/><city quName="江西" pyName="jiangxi" cityname="南昌" state1="2" state2="1" stateDetailed="阴转多云" tem1="23" tem2="15" windState="北风3-4级转微风"/><city quName="广东" pyName="guangdong" cityname="广州" state1="3" state2="2" stateDetailed="阵雨转阴" tem1="26" tem2="20" windState="微风"/><city quName="广西" pyName="guangxi" cityname="南宁" state1="3" state2="3" stateDetailed="阵雨" tem1="23" tem2="19" windState="东北风小于3级"/><city quName="北京" pyName="beijing" cityname="北京" state1="0" state2="0" stateDetailed="晴" tem1="26" tem2="10" windState="微风"/><city quName="天津" pyName="tianjin" cityname="天津" state1="1" state2="0" stateDetailed="多云转晴" tem1="22" tem2="13" windState="东北风3-4级转小于3级"/><city quName="上海" pyName="shanghai" cityname="上海" state1="7" state2="1" stateDetailed="小雨转多云" tem1="20" tem2="16" windState="西北风3-4级"/><city quName="重庆" pyName="chongqing" cityname="重庆" state1="1" state2="3" stateDetailed="多云转阵雨" tem1="21" tem2="14" windState="微风"/><city quName="香港" pyName="xianggang" cityname="香港" state1="3" state2="1" stateDetailed="阵雨转多云" tem1="26" tem2="22" windState="微风"/><city quName="澳门" pyName="aomen" cityname="澳门" state1="3" state2="1" stateDetailed="阵雨转多云" tem1="27" tem2="22" windState="东北风3-4级转微风"/><city quName="台湾" pyName="taiwan" cityname="台北" state1="9" state2="7" stateDetailed="大雨转小雨" tem1="28" tem2="21" windState="微风"/><city quName="西沙" pyName="xisha" cityname="西沙" state1="3" state2="3" stateDetailed="阵雨" tem1="30" tem2="26" windState="东北风4-5级"/><city quName="南沙" pyName="nanshadao" cityname="南沙" state1="1" state2="1" stateDetailed="多云" tem1="32" tem2="27" windState="东风4-5级"/><city quName="钓鱼岛" pyName="diaoyudao" cityname="钓鱼岛" state1="7" state2="1" stateDetailed="小雨转多云" tem1="23" tem2="19" windState="西南风3-4级转北风5-6级"/></china>
确定了访问接口后,我们只需要在代码中按照以下的方式来使用XMLRequest即可:
[java] view plain copy
print?
  1. XMLRequest xmlRequest = new XMLRequest(  
  2.         ”http://flash.weather.com.cn/wmaps/xml/china.xml”,  
  3.         new Response.Listener<XmlPullParser>() {  
  4.             @Override  
  5.             public void onResponse(XmlPullParser response) {  
  6.                 try {  
  7.                     int eventType = response.getEventType();  
  8.                     while (eventType != XmlPullParser.END_DOCUMENT) {  
  9.                         switch (eventType) {  
  10.                         case XmlPullParser.START_TAG:  
  11.                             String nodeName = response.getName();  
  12.                             if (“city”.equals(nodeName)) {  
  13.                                 String pName = response.getAttributeValue(0);  
  14.                                 Log.d(”TAG”“pName is ” + pName);  
  15.                             }  
  16.                             break;  
  17.                         }  
  18.                         eventType = response.next();  
  19.                     }  
  20.                 } catch (XmlPullParserException e) {  
  21.                     e.printStackTrace();  
  22.                 } catch (IOException e) {  
  23.                     e.printStackTrace();  
  24.                 }  
  25.             }  
  26.         }, new Response.ErrorListener() {  
  27.             @Override  
  28.             public void onErrorResponse(VolleyError error) {  
  29.                 Log.e(”TAG”, error.getMessage(), error);  
  30.             }  
  31.         });  
  32. mQueue.add(xmlRequest);  
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);

可以看到,这里XMLRequest的用法和StringRequest几乎是一模一样的,我们先创建出一个XMLRequest的实例,并把服务器接口地址传入,然后在onResponse()方法中解析响应的XML数据,并把每个省的名字打印出来,最后将这个XMLRequest添加到RequestQueue当中。


现在运行一下代码,观察控制台日志,就可以看到每个省的名字都从XML中解析出来了,如下图所示。



2. 自定义GsonRequest


JsonRequest的数据解析是利用Android本身自带的JSONObject和JSONArray来实现的,配合使用JSONObject和JSONArray就可以解析出任意格式的JSON数据。不过也许你会觉得使用JSONObject还是太麻烦了,还有很多方法可以让JSON数据解析变得更加简单,比如说GSON。遗憾的是,Volley中默认并不支持使用自家的GSON来解析数据,不过没有关系,通过上面的学习,相信你已经知道了自定义一个Request是多么的简单,那么下面我们就来举一反三一下,自定义一个GsonRequest。


首先我们需要把gson的jar包添加到项目当中,jar包的下载地址是:https://code.google.com/p/google-gson/downloads/list 。


接着定义一个GsonRequest继承自Request,代码如下所示:

[java] view plain copy
print?
  1. public class GsonRequest<T> extends Request<T> {  
  2.   
  3.     private final Listener<T> mListener;  
  4.   
  5.     private Gson mGson;  
  6.   
  7.     private Class<T> mClass;  
  8.   
  9.     public GsonRequest(int method, String url, Class<T> clazz, Listener<T> listener,  
  10.             ErrorListener errorListener) {  
  11.         super(method, url, errorListener);  
  12.         mGson = new Gson();  
  13.         mClass = clazz;  
  14.         mListener = listener;  
  15.     }  
  16.   
  17.     public GsonRequest(String url, Class<T> clazz, Listener<T> listener,  
  18.             ErrorListener errorListener) {  
  19.         this(Method.GET, url, clazz, listener, errorListener);  
  20.     }  
  21.   
  22.     @Override  
  23.     protected Response<T> parseNetworkResponse(NetworkResponse response) {  
  24.         try {  
  25.             String jsonString = new String(response.data,  
  26.                     HttpHeaderParser.parseCharset(response.headers));  
  27.             return Response.success(mGson.fromJson(jsonString, mClass),  
  28.                     HttpHeaderParser.parseCacheHeaders(response));  
  29.         } catch (UnsupportedEncodingException e) {  
  30.             return Response.error(new ParseError(e));  
  31.         }  
  32.     }  
  33.   
  34.     @Override  
  35.     protected void deliverResponse(T response) {  
  36.         mListener.onResponse(response);  
  37.     }  
  38.   
  39. }  
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);    }}

可以看到,GsonRequest是继承自Request类的,并且同样提供了两个构造函数。在parseNetworkResponse()方法中,先是将服务器响应的数据解析出来,然后通过调用Gson的fromJson方法将数据组装成对象。在deliverResponse方法中仍然是将最终的数据进行回调。


那么下面我们就来测试一下这个GsonRequest能不能够正常工作吧,调用http://www.weather.com.cn/data/sk/101010100.html这个接口可以得到一段JSON格式的天气数据,如下所示:

[plain] view plain copy
print?
  1. {“weatherinfo”:{“city”:”北京”,”cityid”:”101010100”,”temp”:”19”,”WD”:”南风”,”WS”:”2级”,”SD”:”43%”,”WSE”:”2”,”time”:”19:45”,”isRadar”:”1”,”Radar”:”JC_RADAR_AZ9010_JB”}}  
{"weatherinfo":{"city":"北京","cityid":"101010100","temp":"19","WD":"南风","WS":"2级","SD":"43%","WSE":"2","time":"19:45","isRadar":"1","Radar":"JC_RADAR_AZ9010_JB"}}
接下来我们使用对象的方式将这段JSON字符串表示出来。新建一个Weather类,代码如下所示:
[java] view plain copy
print?
  1. public class Weather {  
  2.   
  3.     private WeatherInfo weatherinfo;  
  4.   
  5.     public WeatherInfo getWeatherinfo() {  
  6.         return weatherinfo;  
  7.     }  
  8.   
  9.     public void setWeatherinfo(WeatherInfo weatherinfo) {  
  10.         this.weatherinfo = weatherinfo;  
  11.     }  
  12.   
  13. }  
public class Weather {    private WeatherInfo weatherinfo;    public WeatherInfo getWeatherinfo() {        return weatherinfo;    }    public void setWeatherinfo(WeatherInfo weatherinfo) {        this.weatherinfo = weatherinfo;    }}
Weather类中只是引用了WeatherInfo这个类。接着新建WeatherInfo类,代码如下所示:
[java] view plain copy
print?
  1. public class WeatherInfo {  
  2.   
  3.     private String city;  
  4.   
  5.     private String temp;  
  6.   
  7.     private String time;  
  8.   
  9.     public String getCity() {  
  10.         return city;  
  11.     }  
  12.   
  13.     public void setCity(String city) {  
  14.         this.city = city;  
  15.     }  
  16.   
  17.     public String getTemp() {  
  18.         return temp;  
  19.     }  
  20.   
  21.     public void setTemp(String temp) {  
  22.         this.temp = temp;  
  23.     }  
  24.   
  25.     public String getTime() {  
  26.         return time;  
  27.     }  
  28.   
  29.     public void setTime(String time) {  
  30.         this.time = time;  
  31.     }  
  32.   
  33. }  
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;    }}
WeatherInfo类中含有city、temp、time这几个字段。下面就是如何调用GsonRequest了,其实也很简单,代码如下所示:
[java] view plain copy
print?
  1. GsonRequest<Weather> gsonRequest = new GsonRequest<Weather>(  
  2.         ”http://www.weather.com.cn/data/sk/101010100.html”, Weather.class,  
  3.         new Response.Listener<Weather>() {  
  4.             @Override  
  5.             public void onResponse(Weather weather) {  
  6.                 WeatherInfo weatherInfo = weather.getWeatherinfo();  
  7.                 Log.d(”TAG”“city is ” + weatherInfo.getCity());  
  8.                 Log.d(”TAG”“temp is ” + weatherInfo.getTemp());  
  9.                 Log.d(”TAG”“time is ” + weatherInfo.getTime());  
  10.             }  
  11.         }, new Response.ErrorListener() {  
  12.             @Override  
  13.             public void onErrorResponse(VolleyError error) {  
  14.                 Log.e(”TAG”, error.getMessage(), error);  
  15.             }  
  16.         });  
  17. mQueue.add(gsonRequest);  
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);

可以看到,这里onResponse()方法的回调中直接返回了一个Weather对象,我们通过它就可以得到WeatherInfo对象,接着就能从中取出JSON中的相关数据了。现在运行一下代码,观察控制台日志,打印数据如下图所示:



这样的话,XMLRequest和GsonRequest的功能就基本都实现了,我们也是借助这两个例子深刻地理解了自定义Request的方法,对Volley的认识也是更加深入了。好了,本篇文章就到此结束,下篇文章中我们将对Volley进行更深层次的研究,感兴趣的朋友请继续阅读Android Volley完全解析(四),带你从源码的角度理解Volley


blockquote{ border-left: 10px solid rgba(128,128,128,0.075); background-color: rgba(128,128,128,0.05); border-radius: 0 5px 5px 0; padding: 15px 20px;

关注我的技术公众号,每天都有优质技术文章推送。关注我的娱乐公众号,工作、学习累了的时候放松一下自己。

微信扫一扫下方二维码即可关注:

        

阅读全文
0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 小孩考试太粗心怎么办 带孩子太粗心怎么办 小孩做数学粗心怎么办 小学一年级学生厌学怎么办 小学二年级厌学怎么办 做题做的烦躁了怎么办 英语不会做题怎么办 孩子审题不细心怎么办 生孩子有恐惧症怎么办 小孩不喜欢上幼儿园怎么办 小孩不喜欢去幼儿园怎么办 小孩不喜欢学生字怎么办 学生不喜欢补课老师怎么办 小孩不喜欢上学逃课怎么办 一年级小朋友不爱写字怎么办 幼儿园小朋友不爱写字怎么办 孩子懒散不积极怎么办 孩子不肯上幼儿园怎么办 孩子不肯去幼儿园怎么办 小孩记不住字怎么办 小孩不会写字要怎么办 一年级孩子不爱写字怎么办 一年级小孩不爱写字怎么办 孩子不爱写字怎么办呢 幼儿园孩子不爱写字怎么办 孩子上学没学籍怎么办 孩子上学务工证怎么办 孩子上学被欺负怎么办 孩子害怕上幼儿园怎么办 孩子写字肩膀疼怎么办 5岁不会写字怎么办 上中班不爱写字怎么办 孩子性子太慢怎么办 13小孩特别懒怎么办 小孩不肯上幼儿园怎么办 宝宝不肯上幼儿园怎么办 宝宝不肯去幼儿园怎么办 小孩子不肯去幼儿园怎么办 上幼儿园不说话怎么办 小孩写字不认真怎么办 游戏打开是乱码怎么办