转载请注明出处: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 plaincopy

  1. /** 

  2.  * A canned request for retrieving the response body at a given URL as a String. 

  3.  */  

  4. public class StringRequest extends Request {  

  5.     private final Listener 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 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 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 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. }  

可以看到,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 plaincopy

  1. public class XMLRequest extends Request {  

  2.   

  3.     private final Listener mListener;  

  4.   

  5.     public XMLRequest(int method, String url, Listener listener,  

  6.             ErrorListener errorListener) {  

  7.         super(method, url, errorListener);  

  8.         mListener = listener;  

  9.     }  

  10.   

  11.     public XMLRequest(String url, Listener listener, ErrorListener errorListener) {  

  12.         this(Method.GET, url, listener, errorListener);  

  13.     }  

  14.   

  15.     @Override  

  16.     protected Response 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. }  

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

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

[html] view plaincopy

  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. china>  

确定了访问接口后,我们只需要在代码中按照以下的方式来使用XMLRequest即可:

[java] view plaincopy

  1. XMLRequest xmlRequest = new XMLRequest(  

  2.         "http://flash.weather.com.cn/wmaps/xml/china.xml",  

  3.         new Response.Listener() {  

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


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

Android Volley完全解析(三),定制自己的Request_第1张图片

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 plaincopy

  1. public class GsonRequest extends Request {  

  2.   

  3.     private final Listener mListener;  

  4.   

  5.     private Gson mGson;  

  6.   

  7.     private Class mClass;  

  8.   

  9.     public GsonRequest(int method, String url, Class clazz, Listener 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 clazz, Listener listener,  

  18.             ErrorListener errorListener) {  

  19.         this(Method.GET, url, clazz, listener, errorListener);  

  20.     }  

  21.   

  22.     @Override  

  23.     protected Response 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. }  

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


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

[plain] view plaincopy

  1. {"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 plaincopy

  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. }  

Weather类中只是引用了WeatherInfo这个类。接着新建WeatherInfo类,代码如下所示:

[java] view plaincopy

  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. }  

WeatherInfo类中含有city、temp、time这几个字段。下面就是如何调用GsonRequest了,其实也很简单,代码如下所示:

[java] view plaincopy

  1. GsonRequest gsonRequest = new GsonRequest(  

  2.         "http://www.weather.com.cn/data/sk/101010100.html", Weather.class,  

  3.         new Response.Listener() {  

  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);  

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


Android Volley完全解析(三),定制自己的Request_第2张图片

这样的话,XMLRequest和GsonRequest的功能就基本都实现了,我们也是借助这两个例子深刻地理解了自定义Request的方法,对Volley的认识也是更加深入了。

更多相关文章

  1. Android 通过代码实现控制数据网络的开关(仅适用于5.0以上)
  2. 安卓手机恶意代码——Samsapo
  3. 20172323 2017-2018-2《程序设计与数据结构》第十一周学习总结
  4. Android多文件断点续传(二)——实现数据库储存下载信息
  5. Android5.1系统通过包名给应用开放系统权限的方法
  6. Android MP4取得播放时长的方法
  7. Android中执行java命令的方法及java代码执行并解析shell命令
  8. Android 导入项目时报Android.jar包丢失解决方法

随机推荐

  1. android TextView 滚动条自动滚动最底
  2. android自定义主题样式
  3. Android版本和API Level对应关系
  4. android:inputType参数类型说明
  5. Android(安卓)SDK和最新ADT下载地址
  6. Android(安卓)ui
  7. 改写ListView样式
  8. Android百度地图开发(三):定位
  9. android中的style部分属性值介绍
  10. android隐藏EditText光标