**欢迎访问我的个人博客转发请注明出处:http://www.wensibo.top/2017/02/17/一口一口吃掉Volley(三)/ **

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

从StringRequest开始讲讲思路

先上最基本的StringRequest源码

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:

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改为你所在的省份就可以显示其他数据了:

<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="1级" humidity="37%" time="15:30" url="101281201"/>
<city cityX="492" cityY="217" cityname="汕尾" centername="汕尾" fontColor="FFFFFF" pyName="shanwei" state1="1" state2="0" stateDetailed="多云转晴" tem1="24" tem2="14" temNow="24" windState="东南风3-4级转微风" windDir="东风" windPower="2级" humidity="45%" time="15:30" url="101282101"/>
<city cityX="522.55" cityY="110.45" cityname="梅州" centername="梅州" fontColor="FFFFFF" pyName="meizhou" state1="1" state2="0" stateDetailed="多云转晴" tem1="27" tem2="12" temNow="26" windState="微风" windDir="东风" windPower="1级" humidity="36%" time="15:30" url="101280401"/>
<city cityX="526.8" cityY="182" cityname="揭阳" centername="揭阳" fontColor="FFFFFF" pyName="jieyang" state1="0" state2="0" stateDetailed="晴" tem1="26" tem2="13" temNow="26" windState="微风" windDir="东风" windPower="2级" humidity="34%" time="15:30" url="101281901"/>
<city cityX="579" cityY="137.45" cityname="潮州" centername="潮州" fontColor="FFFFFF" pyName="chaozhou" state1="0" state2="0" stateDetailed="晴" tem1="25" tem2="12" temNow="26" windState="微风" windDir="东南风" windPower="2级" humidity="38%" time="15:30" url="101281501"/>
<city cityX="566.45" cityY="179.25" cityname="汕头" centername="汕头" fontColor="FFFFFF" pyName="shantou" state1="0" state2="1" stateDetailed="晴转多云" tem1="24" tem2="13" temNow="24" windState="东北风转东风小于3级" windDir="东风" windPower="2级" humidity="54%" time="15:30" url="101280501"/>
</guangdong>

③ 调用XMLRequest,并加入RequestQueue

代码中我将解析XML数据的城市展示在List View中:

 XMLRequest xmlRequest = new XMLRequest(
"http://flash.weather.com.cn/wmaps/xml/guangdong.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(2);
Log.d("CITY", "PName is" + pname);
citys.add(pname);
}
break;
}
eventType = response.next();
} ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(XMLRequestActivity.this, android.R.layout.simple_list_item_1, citys);
lv_xml_request.setAdapter(arrayAdapter);
} catch (XmlPullParserException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
lv_xml_request.setVisibility(View.GONE);
mTextView.setVisibility(View.VISIBLE);
Log.d("ERROR", "返回XMLRequest失败");
}
}
);
mQueue.add(xmlRequest);
}

人品爆发,看截图

自定义GsonRequest

虽然Volley提供了JsonRequest为我们解析Json,但是使用JSONObject还是太麻烦了,还有很多方法可以让JSON数据解析变得更加简单,比如说GSON,所以何不如自定义一个GsonRequest呢?思路也是大同小异!

① 直接上代码啦!

public class GsonRequest<T> extends Request<T> {

    private final Response.Listener<T> mListener;
private Gson mGson;
private Class<T> mClazz; public GsonRequest(int method, String url, Class<T> clazz, Response.Listener<T> listener, Response.ErrorListener errorListener) {
super(method, url, errorListener);
mGson = new Gson();
mClazz = clazz;
mListener = 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 {
response.headers.put("HTTP.CONTENT_TYPE", "utf-8");
String jsonString = new String(response.data,"utf-8");
//加上这两行可以解决乱码的问题,尤其是对于中文的json接口,由于每个网页的编码格式不同,所以获取原编码格式之后再转换为utf-8,即可。
return Response.success(mGson.fromJson(jsonString, mClazz),
HttpHeaderParser.parseCacheHeaders(response)
);
} catch (UnsupportedEncodingException e) {
return Response.error(new ParseError(e));
}
} @Override
protected void deliverResponse(T response) {
mListener.onResponse(response);
}
}

同样需要注意编码的问题。在parseNetworkResponse()方法中,先是将服务器响应的数据解析出来,然后通过调用Gson的fromJson方法将数据组装成对象。在deliverResponse方法中仍然是将最终的数据进行回调。

  • 记得为工程加入gson库
compile 'com.google.code.gson:gson:2.8.0'

② json接口

使用之前使用的json接口:http://www.weather.com.cn/data/sk/101010100.html ,它返回的数据是一个叫做weatherinfo的jsonObject:

{"weatherinfo":{"city":"北京","cityid":"101010100","temp":"19","WD":"南风","WS":"2级","SD":"43%","WSE":"2","time":"19:45","isRadar":"1","Radar":"JC_RADAR_AZ9010_JB"}}

③ 新建bean类

由于返回的jsonObject名字叫做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;
}
}

另外还需要再定义一个Weather类,来获取WeatherInfo对象:

public class Weather {
//此处的weatherinfo不可以修改为weatherInfo,因为从json获取的数据格式为
// {"weatherinfo":{"city":"北京","cityid":"101010100","temp":"19","WD":"南风","WS":"2级","SD":"43%","WSE":"2","time":"19:45","isRadar":"1","Radar":"JC_RADAR_AZ9010_JB"}}
private WeatherInfo weatherinfo; public WeatherInfo getWeatherInfo() {
return weatherinfo;
} public void setWeatherInfo(WeatherInfo weatherinfo) {
this.weatherinfo = weatherinfo;
}
}

此处的weatherinfo不可以修改为weatherInfo

④调用GsonRequest

我们将获取的数据显示在Text View上就行了。

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();
if (weatherInfo != null) {
StringBuffer str = new StringBuffer();
str.append("城市:" + weatherInfo.getCity() + "\n");
str.append("温度:" + weatherInfo.getTemp() + "\n");
str.append("时间:" + weatherInfo.gettime());
tv_gson_request.setText(str);
Log.d("SUCCESS", "成功返回GsonRequest " + str.toString());
} else {
Log.d("ERROR", "weatherinfo对象为空");
}
}
}
, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.d("ERROR", "返回GsonRequest失败");
tv_gson_request.setText(getResources().getString(R.string.error_message));
}
}
); mQueue.add(gsonRequest);

看截图啦!

这一节只是向大家介绍了如何自定义Request,其实都是大同小异的,例如你觉得Gson不能满足你,那你也可以改为FastJson或者其他的功能,但是请一定要注意编码问题!最后一节我们将一起通过阅读源码来分析Volley的工作流程!

一口一口吃掉Volley(三)的更多相关文章

  1. 一口一口吃掉Volley(一)

    欢迎访问我的个人博客转发请注明出处:http://www.wensibo.top/2017/02/16/一口一口吃掉Volley(一)/ 本次编写的Volley教程现在看来其实已经跟不上时代了,但是技 ...

  2. 一口一口吃掉Volley(二)

    欢迎访问我的个人博客转发请注明出处:http://www.wensibo.top/2017/02/17/一口一口吃掉Volley(二)/ 相信看了第一篇教程之后,你应该会对Volley有一个初步的了解 ...

  3. 一口一口吃掉Volley(四)

    欢迎访问我的个人博客转发请注明出处:http://www.wensibo.top/2017/02/17/一口一口吃掉Volley(四)/ 非常感谢你能够坚持看到第四篇,同时这也是这个Volley系列教 ...

  4. 一口一口吃掉Hibernate(五)——一对多单向关联映射

    版权声明:本文为博主原创文章,未经博主允许不得转载.如需转载请声明:[转自 http://blog.csdn.net/xiaoxian8023 ] 在上一篇博客<一口一口吃掉Hibernate( ...

  5. 一口一口吃掉Hexo(三)

    如果你想得到更好的阅读效果,请访问我的个人网站 ,版权所有,未经许可不得转载! 相信通过前一节的学习,你已经在你的本地部署好了你的网站,那么接下来就让你的朋友们通过网络访问你的网站吧!通过这一节你将免 ...

  6. 一口一口吃掉Hibernate(七)——继承映射

    前几篇博文中讲到了常用的几种关联映射.其实hibernate中还有一种"省劲儿"的映射,那就是--"继承映射". 学了这么多的关系映射了,继承映射,从字面上也能 ...

  7. 一口一口吃掉Hibernate(六)——多对多关联映射

    今天来说说hibernate中的多对多关联映射,多对多关联映射涉及到单向映射和双向映射2种. 首先举个多对多关联例子:用户User和角色Role,一个用户可以属于多个角色,一个角色可以有多个用户.这就 ...

  8. 一口一口吃掉Hibernate(八)——Hibernate中inverse的用法

    一.Inverse是hibernate双向关系中的基本概念.inverse的真正作用就是指定由哪一方来维护之间的关联关系.当一方中指定了“inverse=false”(默认),那么那一方就有责任负责之 ...

  9. 一口一口吃掉Hexo(一)

    如果你想得到更好的阅读效果,请访问我的个人网站 ,版权所有,未经许可不得转载! 这里是我的个人博客网站,点击这里你可以到我的首页瞧瞧.我之前使用的是第三方的博客平台--博客园,点击这里可以看到我的博客 ...

随机推荐

  1. 恢复VS2010/VS2013项目为VS2008项目

    https://blogs.msdn.microsoft.com/rextang/2009/07/06/convert-vs2010-projects-back-to-vs2008-ones/ 摘抄如 ...

  2. AI模型训练/算法评估 测试员

  3. 12.DataGrid的columns的特性

  4. hdu 1.2.6

    勾股定理... #include<cstdio> #include<algorithm> using namespace std; int main() { //freopen ...

  5. nuget.org无法解析的办法

    今天想学习ef框架,就着手安装最新的ef啦.可是遇到了问题,提示 未能解析此远程名称:'nuget.org' 就去上网找资料啦,发现原来是被墙了,表示无奈. 网上的资料提示,修改hosts文件或是dn ...

  6. ASP.NET MVC高亮显示当前页面菜单

    1.创建MvcHtmlExtension扩展类 public static class MvcHtmlExtension { public static MvcHtmlString MenuLink( ...

  7. 用Socket来简单实现IIS服务器

    刚刚接触ASP.NET编程,为了更好的屡清楚服务器的处理过程,就用Socket模拟服务器来处理请求.用Socket来模拟服务器的时候,同样是自己来封装一些对应的类文件.包括 HttpRequest.H ...

  8. Could not load file or assembly 'Microsoft.AnalysisServices.SharePoint.Integration'

    In Central Administration, in System Settings, click Manage farm solutions. Click Powerpivotwebapp. ...

  9. Download SQL Server Management Studio (SSMS)下载地址

    Download SQL Server Management Studio (SSMS)下载地址: https://msdn.microsoft.com/en-us/library/mt238290. ...

  10. 201621123018《Java程序设计》第5周学习报告

    1. 本周学习总结 1.1 写出你认为本周学习中比较重要的知识点关键词 接口.interface.implements.Comparable.Comparator. 1.2 尝试使用思维导图将这些关键 ...