Volley框架的使用--自定义数据的请求方式
来源: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,这也就是本篇文章的主题了。
1. 自定义XMLRequest
/** * 定义自己的XMLRequest请求方式 */ public class MainActivity extends Activity { /** * 请求队列,RequestQueue内部的设计就是非常合适高并发的,因此我们不必为每一次HTTP请求都创建一个RequestQueue对象 * 基本上在每一个需要和网络交互的Activity中创建一个RequestQueue对象就足够了。 */ private RequestQueue requestQueue; private ImageView imageView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); imageView = (ImageView) findViewById(R.id.imageView); //第一步:创建网络请求队列 requestQueue = Volley.newRequestQueue(this); String url="http://wthrcdn.etouch.cn/WeatherApi?city=%E5%8C%97%E4%BA%AC"; XMLRequest xmlRequest = new XMLRequest(Request.Method.GET, url, new Response.Listener<XmlPullParser>() { @Override public void onResponse(XmlPullParser xmlPullParser) { //XMLRequest类里方法的回调 try { int code=xmlPullParser.getEventType(); while(code!=1){ String name = xmlPullParser.getName(); switch (code){ case 2: if("date".equals(name)){ Log.i("tag",xmlPullParser.nextText()); } break; } code=xmlPullParser.next(); } } catch (Exception e) { e.printStackTrace(); } } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError volleyError) { Log.i("tag","下载失败"+volleyError.getMessage()); } }); requestQueue.add(xmlRequest); } /** * 模仿字符串请求,自定义Xml请求的方式: * 其实就是将网址传过来下载了数据后在Response方法中将数据添加到解析器,然后用接口回调把解析器传出去 */ class XMLRequest extends Request<XmlPullParser> { private Response.Listener<XmlPullParser> mListener; public XMLRequest(int method, String url, Response.Listener<XmlPullParser> listener, Response.ErrorListener errorListener) { super(method, url, errorListener); mListener = listener; } /** * 对服务器响应的数据进行解析,其中数据是以字节的形式存放在NetworkResponse的data变量中的, * 这里将数据取出然后组装成一个String,并传入Response的success()方法中即可 */ @Override protected Response<XmlPullParser> parseNetworkResponse(NetworkResponse networkResponse) { try { XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); XmlPullParser xmlPullParser = factory.newPullParser(); //得到连接网络下载的数据,指定了编码格式 String xmlData=new String(networkResponse.data,"utf-8");//不然会乱码 //设置Pull解析的数据源 xmlPullParser.setInput(new StringReader(xmlData)); return Response.success(xmlPullParser, HttpHeaderParser.parseCacheHeaders(networkResponse)); } catch (XmlPullParserException e) { e.printStackTrace(); return Response.error(new ParseError(e)); } catch (UnsupportedEncodingException e) { e.printStackTrace(); return Response.error(new ParseError(e)); } } @Override protected void deliverResponse(XmlPullParser xmlPullParser) { //将携带了数据的解析器传出去(接口回调) mListener.onResponse(xmlPullParser); } } } /*字符串请求方式的源码: public class StringRequest extends Request<String> { protected Response<String> parseNetworkResponse(NetworkResponse response) { String parsed; try { parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers));//这里编码为"ISO-8859-1" } catch (UnsupportedEncodingException var4) { parsed = new String(response.data); } return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response)); } } */
自定义字符串的请求方式,其实上面也可以直接得到从网络上获取的数据,然后在回调方法里进行数据解析就行了
2.获取字符串数据,保证不乱码:
public class MainActivity extends Activity { /** * 请求队列,RequestQueue内部的设计就是非常合适高并发的,因此我们不必为每一次HTTP请求都创建一个RequestQueue对象 * 基本上在每一个需要和网络交互的Activity中创建一个RequestQueue对象就足够了。 */ private RequestQueue requestQueue; private ImageView imageView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); imageView = (ImageView) findViewById(R.id.imageView); //第一步:创建网络请求队列 requestQueue = Volley.newRequestQueue(getApplicationContext()); String url="http://www.baidu.com"; //String url="http://wthrcdn.etouch.cn/WeatherApi?city=%E5%8C%97%E4%BA%AC"; XMLRequest xmlRequest = new XMLRequest(Request.Method.GET, url, new Response.Listener<String>() { @Override public void onResponse(String s) { //这样就能得到任意网址的字符串数据了,而且还不会乱码, 在这里再进行数据解析也是一样的 Log.i("tag", "下载成功,s=" + s); } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError volleyError) { Log.i("tag", "下载失败"); } }); requestQueue.add(xmlRequest); } /** * 模仿字符串请求,自定义请求的方式: */ class XMLRequest extends Request<String> { private Response.Listener<String> mlistener; public XMLRequest(int method, String url, Response.Listener<String> succedlistener, Response.ErrorListener listener) { super(method, url, listener); mlistener=succedlistener; } @Override protected Response<String> parseNetworkResponse(NetworkResponse networkResponse) { String parsed; try { parsed = new String(networkResponse.data, "utf-8");//这里源码的编码为"ISO-8859-1" Log.i("tag","parsed="+parsed); } catch (UnsupportedEncodingException var4) { parsed = new String(networkResponse.data); } return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(networkResponse)); } @Override protected void deliverResponse(String s) { mlistener.onResponse(s); } } }
3. 自定义Json数据的请求(这里利用Gson解析的),实体类利用工具自动生成的,就不码出来了
public class MainActivity extends AppCompatActivity { private RequestQueue requestQueue; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); requestQueue = Volley.newRequestQueue(this);//创建网络请求队列(执行网络连接的) //json数据的网址 String s = "http://zhushouapi.gamedog.cn/index.php?umengchannel=baidu&m=Android&a=lists&channel=youxi&order=down&page=1&pagesize=8"; GameDog dog = new GameDog(Request.Method.GET, s, new Response.Listener<GameDogBean>() { @Override public void onResponse(GameDogBean response) { //第三步:主线程运行的,得到传过来的结果 Log.i("tag", "解析出来的对象:" + response.getData().get(0).getRemark()); } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { Log.i("tag", "解析出错"); } }); requestQueue.add(dog);//执行任务 } /** * 定义自己的解析方式 */ class GameDog extends Request<GameDogBean>{ private Response.Listener<GameDogBean> mListener;//请求成功的回调对象 public GameDog(int method, String url, Response.Listener<GameDogBean> listener1, Response.ErrorListener listener) { super(method, url, listener); mListener = listener1; } @Override protected Response<GameDogBean> parseNetworkResponse(NetworkResponse response) { //第一步:子线程运行 String jsonData; try { //将下载下来的字节数组,转换为字符串, 第二个参数为编码格式 jsonData = new String(response.data, HttpHeaderParser.parseCharset(response.headers)); } catch (Exception e) { jsonData = new String(response.data); } //得到数据后解析数据 Gson gson = new Gson(); GameDogBean bean = gson.fromJson(jsonData, GameDogBean.class);//GameDogBean为用工具生成的json数据实体类 return Response.success(bean, HttpHeaderParser.parseCacheHeaders(response));//将调用deliverResponse() } @Override protected void deliverResponse(GameDogBean response) { //第二步:主线程运行的,将结果回调出去 mListener.onResponse(response); } } }
这样就把具体的解析过程放到内部子线程里了,外面只需要得到传回来的json对象获取数据就行