Android开发——Volley的使用具体解释
0. 前言
Android系统中主要提供了HttpURLConnection和HttpClient进行网络通信。可是假设不正确其进行封装就很easy就会写出反复代码。因此一些Android网络通信框架应运而生, Volley就是当中的佼佼者,Volley不仅能够进行HTTP通信,也能够轻松载入网络上的图片。Volley设计的初衷就是很适合去进行数据量不大,但通信频繁的网络操作,而对于大数据量的网络操作。比方说下载文件等。Volley的表现就会很糟糕。原因总结例如以下:
(1)Volley的网络请求线程池默觉得4。因此仅仅能并发进行4个请求(多了排队),easy被4个较大文件的下载任务堵塞其余请求。
(2)Request的parseNetWorkResponse()方法返回byte[]类型。须要把传输到的数据读到内存中。假设文件过大,easy引发OOM。
1. Volley的基本使用
1.1 HTTP GET请求
首先在AS中导入Volley的jar包。
RequestQueue mQueue = Volley.newRequestQueue(getApplicationContext()); StringRequest stringRequest_get = new StringRequest("http://www.baidu.com", new Response.Listener<String>() { @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地址,第二/三个參数是server响应成功/失败的回调。若成功则将返回的html代码转为String打印出log。
1.2 HTTP POST请求
RequestQueue mQueue = Volley.newRequestQueue(getApplicationContext()); StringRequest stringRequest = new StringRequest(Method.POST, url, listener, errorListener) { @Override protected Map<String, String> getParams() throws AuthFailureError { Map<String, String> map = new HashMap<String, String>(); 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是一个抽象类,有两个子类JsonObjectRequest和JsonArrayRequest。前者用于请求一段JSON数据的,后者用于请求一段JSON数组。以下是使用前者进行一段Json请求的范例代码。
//队列初始化以及request增加队列略 JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(url, null, new Response.Listener<JSONObject>() { @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<Bitmap>() { @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<String, Bitmap> mCache; public BitmapCache() { //缓存图片的大小设置为10M int maxSize = 10 * 1024 * 1024; mCache = new LruCache<String, Bitmap>(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对象,传入參数比較简单,看名字就知道了。第四行调用ImageLoader的get()方法来载入图片。
1.6 NetworkImageView
这是第三种载入图片的方式。相对来说也是被用的比較多的方式。NetworkImageView继承自ImageView的。在原生的基础之上增加了载入网络图片的功能。使用方法仍旧是先创建一个RequestQueue对象和一个ImageLoader对象。接下来是在xml中定义我们的NetworkImageView。宽高表示裁剪到此宽高,wrap_content表示不裁剪。
<com.android.volley.toolbox.NetworkImageView android:id="@+id/network_image_view" android:layout_width="100dp" android:layout_height="100dp"/>
在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
在网络上传输的数据经常使用到XML和JSON格式,那么假设想要请求一条XML/JSON格式的数据就须要拓展我们的Volley。
2. 1 XMLRequest
public class StringRequest extends Request<String> { private final Listener<String> mListener; public StringRequest(int method, String url, Listener<String> listener, ErrorListener errorListener) { super(method, url, errorListener); mListener = listener; } public StringRequest(String url, Listener<String> listener, ErrorListener errorListener) { this(Method.GET, url, listener, errorListener); } @Override protected void deliverResponse(String response) { mListener.onResponse(response); } @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)); } }
拓展之前先要看一下原有的Request的子类是怎样实现的。上面以StringRequest为例。StringRequest中提供了两个有參的构造函数,參数包含请求类型,请求地址,以及响应回调等。在构造函数中一定要调用super()方法将这几个參数传给父类,由于HTTP的请求和响应都是在父类中处理的。
由于Request类中的deliverResponse()和parseNetworkResponse()是两个抽象方法。因此StringRequest中对这两个方法进行了实现。前者调用了mListener中的onResponse()方法,并将response内容传入即完毕了将server响应的数据进行回调。
后者对server响应的数据进行解析,当中数据是以字节的形式存放在NetworkResponse的data变量中(前言中在Volley为什么不适合大文件下载就讲到了)。这里将数据取出然后组装成一个String,并传入Response的success()方法中。
在了解了StringRequest之后,我们自己定义实现我们的XMLRequest。
public class XMLRequest extends Request<XmlPullParser> { private final Listener<XmlPullParser> mListener; public XMLRequest(int method, String url, Listener<XmlPullParser> listener, ErrorListener errorListener) { super(method, url, errorListener); mListener = listener; } public XMLRequest(String url, Listener<XmlPullParser> listener, ErrorListener errorListener) { this(Method.GET, url, listener, errorListener); } @Override protected void deliverResponse(XmlPullParser response) { mListener.onResponse(response); } @Override protected Response<XmlPullParser> 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)); } } } //使用我们的XMLRequest XMLRequest xmlRequest = new XMLRequest( url_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 (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解析有多方便,这里能够把Volley和Gson结合在一起吗?当然能够。重写代码基本上大同小异。前提是先导入Gson的jar包。
public class GsonRequest<T> extends Request<T> { private final Listener<T> mListener; private Gson mGson; private Class<T> mClass; public GsonRequest(int method, String url, Class<T> clazz, Listener<T> listener, ErrorListener errorListener) { super(method, url, errorListener); mGson = new Gson(); mClass = clazz; mListener = listener; } public GsonRequest(String url, Class<T> clazz, Listener<T> listener, ErrorListener errorListener) { this(Method.GET, url, clazz, listener, errorListener); } @Override protected Response<T> 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); } } //使用我们的GsonRequest GsonRequest<Weather> gsonRequest = new GsonRequest<Weather>(url_json,YourClass.class, new Response.Listener<Weather>() { @Override public void onResponse(YourClass obj) { //这里获得obj相应的json中的数据 } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { Log.e("TAG", error.getMessage(), error); } });