博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android开发——Volley的使用详解
阅读量:4045 次
发布时间:2019-05-24

本文共 10042 字,大约阅读时间需要 33 分钟。

0. 前言  

Android系统中主要提供了HttpURLConnectionHttpClient进行网络通信,但是如果不对其进行封装就很容易就会写出重复代码。因此一些Android网络通信框架应运而生, Volley就是其中的佼佼者,Volley不仅可以进行HTTP通信,也可以轻松加载网络上的图片Volley设计的初衷就是非常适合去进行数据量不大,但通信频繁的网络操作,而对于大数据量的网络操作,比如说下载文件等,Volley的表现就会非常糟糕。原因总结如下:

1Volley的网络请求线程池默认为4。因此只能并发进行4个请求(多了排队),容易被4个较大文件的下载任务阻塞其余请求

2RequestparseNetWorkResponse()方法返回byte[]类型,需要把传输到的数据读到内存中。如果文件过大,容易引发OOM

 

1.  Volley的基本使用

1.1  HTTP GET请求

首先在AS中导入

RequestQueue mQueue = Volley.newRequestQueue(getApplicationContext());StringRequest stringRequest_get = new StringRequest("http://www.baidu.com",       new Response.Listener
() { @Override public void onResponse(String response) { Log.d("TAG", response); } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { Log.e("TAG", error.getMessage(), error); } });mQueue.add(stringRequest);

StringRequest的构造函数需要传入三个参数,第一个是URL地址,第二/三个参数是服务器响应成功/失败的回调。若成功则将返回的html代码转为String打印出log

1.2  HTTP POST请求

RequestQueue mQueue = Volley.newRequestQueue(getApplicationContext());StringRequest stringRequest = new StringRequest(Method.POST, url, listener, errorListener) {      @Override      protected Map
getParams() throws AuthFailureError { Map
map = new HashMap
(); map.put("params1", "value1"); map.put("params2", "value2"); return map; } }; mQueue.add(stringRequest);

当发出POST请求的时候,Volley会尝试调用StringRequest的父类中的getParams()方法来获取POST参数,因此我们需要在StringRequest中重写getParams()方法,设置POST参数即可。

1.3  JsonRequest

StringRequest一样,JsonRequest也是继承自Request类的 JsonRequest是一个抽象类,有两个子类JsonObjectRequestJsonArrayRequest,前者用于请求一段JSON数据的,后者用于请求一段JSON数组。下面是使用前者进行一段Json请求的范例代码。

//队列初始化以及request加入队列略JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(url, null,          new Response.Listener
() { @Override public void onResponse(JSONObject response) { Log.d("TAG", response.toString()); } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { Log.e("TAG", error.getMessage(), error); } });

1.4  ImageRequest

Volley支持对图片的加载,因为ImageRequest也是继承自Request类,因此用法也大同小异。下面直接传入图片url,返回数据后内部解析为bitmap,最后设置给ImageView。否则设置默认图片。

ImageRequest imageRequest = new ImageRequest(url_image,          new Response.Listener
() { @Override public void onResponse(Bitmap response) { imageView.setImageBitmap(response); } }, 0, 0, Config.RGB_565, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { imageView.setImageResource(R.drawable.default_image); } });

需要注意的是,第三/四个参数用于指定允许图片最大的宽/,若网络图片的实际宽高大于该设定值,则会对图片进行压缩,指定成0的话就表示不进行压缩。第五个参数用于指定图片的颜色属性Bitmap.Config下的几个常量都可以在这里使用,其中ARGB_8888可以展示最好的颜色属性,每个图片像素占据4个字节的大小,而RGB_565则表示每个图片像素占据2个字节大小。不过这种加载图片的方式并不被推荐,因为下面有更好的。

1.5  ImageLoader

ImageLoader基于ImageRequest实现,并且更加智能,多出了帮图片缓存的功能,还可以过滤掉重复的请求链接。但是ImageLoader已经不再继承自Request类。

//mQueue初始化略ImageLoader imageLoader = new ImageLoader(mQueue, new BitmapCache());ImageListener listener = ImageLoader.getImageListener(imageView,  R.drawable.default_image, R.drawable.failed_image);  imageLoader.get(url_image, listener, 200, 200);  //限制最大宽高public class BitmapCache implements ImageCache {     //内部使用LRU实现     private LruCache
mCache; public BitmapCache() { //缓存图片的大小设置为10M int maxSize = 10 * 1024 * 1024; mCache = new LruCache
(maxSize) { @Override protected int sizeOf(String key, Bitmap bitmap) { return bitmap.getRowBytes() * bitmap.getHeight(); } }; } @Override public Bitmap getBitmap(String url) { return mCache.get(url); } @Override public void putBitmap(String url, Bitmap bitmap) { mCache.put(url, bitmap); } }

第二行构造一个ImageLoader对象,其中第二个参数是一个ImageCache对象,参数二为自定义的用户缓存的类BitmapCache,该类继承了ImageCache。第三行获取一个ImageListener对象,传入参数比较简单,看名字就知道了。第四行调用ImageLoaderget()方法来加载图片。

 

1.6  NetworkImageView

这是第三种加载图片的方式,相对来说也是被用的比较多的方式。NetworkImageView继承自ImageView的,在原生的基础之上加入了加载网络图片的功能。用法仍旧是先创建一个RequestQueue对象和一个ImageLoader对象。接下来是在xml中定义我们的NetworkImageView,宽高表示裁剪到此宽高,wrap_content表示不裁剪。

Activity中获取到NetworkImageView实例后,就可以调用它的setDefaultImageResId()方法、setErrorImageResId()方法和setImageUrl()方法来分别设置加载时显示的图片,加载失败时显示的图片,以及目标图片的URL地址。

networkImageView.setDefaultImageResId(R.drawable.default_image);  networkImageView.setErrorImageResId(R.drawable.failed_image);  networkImageView.setImageUrl(url_image,imageLoader);

2.  自定义Request

在网络上传输的数据常用到XMLJSON格式,那么如果想要请求一条XML/JSON格式的数据就需要拓展我们的Volley

 

2. 1  XMLRequest

public class StringRequest extends Request
{ private final Listener
mListener; public StringRequest(int method, String url, Listener
listener, ErrorListener errorListener) { super(method, url, errorListener); mListener = listener; } public StringRequest(String url, Listener
listener, ErrorListener errorListener) { this(Method.GET, url, listener, errorListener); } @Override protected void deliverResponse(String response) { mListener.onResponse(response); } @Override protected Response
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)); } }

拓展之前先要看一下原有的Request的子类是如何实现的,上面以StringRequest为例。StringRequest中提供了两个有参的构造函数,参数包括请求类型,请求地址,以及响应回调等,在构造函数中一定要调用super()方法将这几个参数传给父类,因为HTTP的请求和响应都是在父类中处理的。

由于Request类中的deliverResponse()parseNetworkResponse()是两个抽象方法,因此StringRequest中对这两个方法进行了实现。前者调用了mListener中的onResponse()方法,并将response内容传入即完成了将服务器响应的数据进行回调。后者对服务器响应的数据进行解析,其中数据是以字节的形式存放在NetworkResponsedata变量中(前言中在Volley为什么不适合大文件下载就讲到了),这里将数据取出然后组装成一个String,并传入Responsesuccess()方法中。

在了解了StringRequest之后,我们自定义实现我们的XMLRequest

public class XMLRequest extends Request
{ private final Listener
mListener; public XMLRequest(int method, String url, Listener
listener, ErrorListener errorListener) { super(method, url, errorListener); mListener = listener; } public XMLRequest(String url, Listener
listener, ErrorListener errorListener) { this(Method.GET, url, listener, errorListener); } @Override protected void deliverResponse(XmlPullParser response) { mListener.onResponse(response); } @Override protected Response
parseNetworkResponse(NetworkResponse response) { try { //先转为字符串 String xmlString = new String(response.data, HttpHeaderParser.parseCharset(response.headers)); //重点在于解析xml XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); XmlPullParser xmlPullParser = factory.newPullParser(); xmlPullParser.setInput(new StringReader(xmlString)); //返回XmlPullParser实例 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)); } } } //使用我们的XMLRequestXMLRequest xmlRequest = new XMLRequest( url_xml, new Response.Listener
() { @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 (WANTED_TAG.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); } });

2. 2  GsonRequest

用过Gson的都知道Gson解析有多方便,这里可以把VolleyGson结合在一起吗?当然可以。重写代码基本上大同小异。前提是先导入

public class GsonRequest
extends Request
{ private final Listener
mListener; private Gson mGson; private Class
mClass; public GsonRequest(int method, String url, Class
clazz, Listener
listener, ErrorListener errorListener) { super(method, url, errorListener); mGson = new Gson(); mClass = clazz; mListener = listener; } public GsonRequest(String url, Class
clazz, Listener
listener, ErrorListener errorListener) { this(Method.GET, url, clazz, listener, errorListener); } @Override protected Response
parseNetworkResponse(NetworkResponse response) { try { String jsonString = new String(response.data, HttpHeaderParser.parseCharset(response.headers)); //结合Gson解析 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); } } //使用我们的GsonRequestGsonRequest
gsonRequest = new GsonRequest
(url_json,YourClass.class, new Response.Listener
() { @Override public void onResponse(YourClass obj) { //这里获得obj对应的json中的数据 } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { Log.e("TAG", error.getMessage(), error); } });

转载地址:http://ikzci.baihongyu.com/

你可能感兴趣的文章
Flume 的可靠性级别有哪些?
查看>>
Sqoop 是什么?Sqoop 有什么特点?
查看>>
Sqoop 的使用场景分析
查看>>
DAGScheduler 是什么?有什么作用?
查看>>
DAGScheduler 是如何划分 Stage 的?
查看>>
TaskScheduler 是什么?有什么作用?
查看>>
一篇文章搞懂 DAGScheduler 的调度流程
查看>>
SparkEnv 是什么?有什么作用?
查看>>
SparkConf 是什么?有什么作用?
查看>>
SecurityManager 是什么?有什么作用?
查看>>
如何理解 Java 的线程中断机制?
查看>>
线程的挂起(suspend)和继续执行(resume)是什么情况?
查看>>
线程的等待线程结束(join)和谦让(yield)是什么情况?
查看>>
finalize 真的一点用没有吗?
查看>>
关于HDU 1713 相遇周期
查看>>
BF算法
查看>>
poj 1068 Parencodings 大模拟 水题 暑假第7题
查看>>
poj 2996 Help Me with the Game 暑假第10题 模拟 大水
查看>>
hdu 1937 Finding Seats 尺取法
查看>>
hdu 1941 Justice League 无向完全图
查看>>