学习了一口一口吃掉Volley(二)之后,你应该已经学会了如何使用Volley自带的Request,但是有的时候我们需要解析的数据多种多样,例如XML又或者你想使用Google的gson,那么当Volley不能直接提供给我们这些功能的时候就需要我们进行自定义了,第一节我也向大家讲过Volley面向接口编程,使得其很容易扩展,那么这节课我们就一起来学习自定义的Request吧!

从StringRequest开始讲讲思路

先上最基本的StringRequest源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public class StringRequest extends Request<String>{
private final Response.Listener<String> mListener;
/** 根据给定的METHOD设置对应的request. */
public StringRequest(int method, String url, Response.Listener<String> listener,
Response.ErrorListener errorListener) {
super(method, url, errorListener);
mListener = listener;
}
/** 默认为GET请求的request. */
public StringRequest(String url, Response.Listener<String> listener,
Response.ErrorListener errorListener) {
this(Method.GET, url, listener, errorListener);
}
/** 将HTTP请求结果转换为String. */
@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));
}
/** 将解析的String结果传递给用户的回调接口. */
@Override
protected void deliverResponse(String response) {
mListener.onResponse(response);
}
}

我们应该可以提炼出如下几点:

  • StringRequest继承自Request类,并制定其泛型为String,那么当我们自定义XMLRequest时就应该指定类型为XmlPullParser。
  • 有两个构造函数,默认使用的GET请求。
  • 由于Request类中的deliverResponse()和parseNetworkResponse()是两个抽象方法,因此自定义Request中需要对这两个方法进行实现。
  • deliverResponse()方法中仅仅是调用了mListener中的onResponse()方法,并将response内容传入即可,这样就可以将服务器响应的数据进行回调。
  • parseNetworkResponse()方法中则是对服务器响应的数据进行解析,其中数据是以字节的形式存放在NetworkResponse的response变量中的,这里将数据取出然后组装成一个String,并传入Response的success()方法中即可。
    既然知道内部实现的逻辑,那就开始动手吧!

自定义XMLRequest

① 直接上代码啦!
按照刚才我们解析StringRequest得到的几点结论,我们应该不难得到XMLRequest:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public class XMLRequest extends Request<XmlPullParser> {
private final Response.Listener<XmlPullParser> mListener;
public XMLRequest(int method, String url, Response.Listener<XmlPullParser> listener, Response.ErrorListener errorListener) {
super(method, url, errorListener);
mListener = 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 {
response.headers.put("HTTP.CONTENT_TYPE", "utf-8");
String xmlString = new String(response.data,"utf-8");
//加上这两行可以解决乱码的问题,尤其是对于中文的xml接口,由于每个xml的编码格式不同,所以获取原编码格式之后再转换为utf-8,即可。
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
XmlPullParser xmlPullParser = factory.newPullParser();
xmlPullParser.setInput(new StringReader(xmlString));
Log.d("SUCCESS", "xmlString的内容为" + 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);
}
}

这里需要注意的一点我在上一篇文章中也已经提到了,就是在解析数据的时候如果出现乱码应该转换编码为utf-8。

② 测试接口
作为测试,我使用的XML接口是:http://flash.weather.com.cn/wmaps/xml/guangdong.xml ,它返回的是广东省各个城市的天气预报,你也可以将guangdong改为你所在的省份就可以显示其他数据了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<guangdong dn="day">
<city cityX="137.7" cityY="385.95" cityname="湛江" centername="湛江" fontColor="FFFFFF" pyName="zhanjiang" state1="1" state2="1" stateDetailed="多云" tem1="23" tem2="16" temNow="24" windState="微风" windDir="东南风" windPower="2级" humidity="50%" time="15:30" url="101281001"/>
<city cityX="170.65" cityY="317.55" cityname="茂名" centername="茂名" fontColor="FFFFFF" pyName="maoming" state1="1" state2="1" stateDetailed="多云" tem1="26" tem2="14" temNow="26" windState="微风" windDir="西南风" windPower="1级" humidity="47%" time="15:30" url="101282001"/>
<city cityX="225" cityY="245" cityname="云浮" centername="云浮" fontColor="FFFFFF" pyName="yunfu" state1="1" state2="1" stateDetailed="多云" tem1="26" tem2="13" temNow="26" windState="微风" windDir="东风" windPower="2级" humidity="43%" time="15:30" url="101281401"/>
<city cityX="226.55" cityY="304.5" cityname="阳江" centername="阳江" fontColor="FFFFFF" pyName="yangjiang" state1="0" state2="1" stateDetailed="晴转多云" tem1="24" tem2="15" temNow="23" windState="微风" windDir="东南风" windPower="3级" humidity="63%" time="15:30" url="101281801"/>
<city cityX="275.35" cityY="214.65" cityname="肇庆" centername="肇庆" fontColor="FFFFFF" pyName="zhaoqing" state1="1" state2="1" stateDetailed="多云" tem1="26" tem2="14" temNow="26" windState="微风" windDir="西北风" windPower="1级" humidity="43%" time="15:30" url="101280901"/>
<city cityX="291" cityY="285" cityname="江门" centername="江门" fontColor="FFFFFF" pyName="jiangmen" state1="0" state2="0" stateDetailed="晴" tem1="26" tem2="15" temNow="26" windState="微风" windDir="东风" windPower="2级" humidity="38%" time="15:30" url="101281101"/>
<city cityX="313.3" cityY="160.45" cityname="清远" centername="清远" fontColor="FFFFFF" pyName="qingyuan" state1="1" state2="1" stateDetailed="多云" tem1="25" tem2="15" temNow="26" windState="微风" windDir="南风" windPower="2级" humidity="44%" time="15:30" url="101281301"/>
<city cityX="308.7" cityY="225" cityname="佛山" centername="佛山" fontColor="FFFFFF" pyName="foshan" state1="0" state2="1" stateDetailed="晴转多云" tem1="26" tem2="14" temNow="26" windState="微风" windDir="北风" windPower="1级" humidity="42%" time="15:30" url="101280800"/>
<city cityX="342.7" cityY="255" cityname="中山" centername="中山" fontColor="FFFFFF" pyName="zhongshan" state1="1" state2="1" stateDetailed="多云" tem1="25" tem2="14" temNow="26" windState="微风" windDir="西北风" windPower="2级" humidity="41%" time="15:30" url="101281701"/>
<city cityX="340.55" cityY="300" cityname="珠海" centername="珠海" fontColor="FFFFFF" pyName="zhuhai" state1="1" state2="1" stateDetailed="多云" tem1="23" tem2="17" temNow="23" windState="微风" windDir="东风" windPower="2级" humidity="48%" time="15:30" url="101280701"/>
<city cityX="352.6" cityY="80" cityname="韶关" centername="韶关" fontColor="FFFFFF" pyName="shaoguan" state1="1" state2="1" stateDetailed="多云" tem1="25" tem2="14" temNow="27" windState="微风" windDir="西风" windPower="1级" humidity="34%" time="15:30" url="101280201"/>
<city cityX="353" cityY="196" cityname="广州" centername="广州" fontColor="FFFF00" pyName="guangzhou" state1="0" state2="0" stateDetailed="晴" tem1="26" tem2="14" temNow="26" windState="微风" windDir="南风" windPower="1级" humidity="40%" time="15:20" url="101280101"/>
<city cityX="377" cityY="234" cityname="东莞" centername="东莞" fontColor="FFFFFF" pyName="dongguan" state1="0" state2="1" stateDetailed="晴转多云" tem1="25" tem2="15" temNow="26" windState="微风" windDir="北风" windPower="1级" humidity="37%" time="15:30" url="101281601"/>
<city cityX="409" cityY="257" cityname="深圳" centername="深圳" fontColor="FFFFFF" pyName="shenzhen" state1="0" state2="0" stateDetailed="晴" tem1="24" tem2="15" temNow="24" windState="微风" windDir="南风" windPower="3级" humidity="49%" time="15:30" url="101280601"/>
<city cityX="423.85" cityY="214.65" cityname="惠州" centername="惠州" fontColor="FFFFFF" pyName="huizhou" state1="1" state2="0" stateDetailed="多云转晴" tem1="26" tem2="13" temNow="26" windState="微风" windDir="南风" windPower="1级" humidity="38%" time="15:20" url="101280301"/>
<city cityX="442.55" cityY="141.6" cityname="河源" centername="河源" fontColor="FFFFFF" pyName="heyuan" state1="0" state2="1" stateDetailed="晴转多云" tem1="25" tem2="15" temNow="27" windState="微风" windDir="西南风" windPower=