为什么要使用Volley?
开发者在处理HTTP请求的时候,通常需要创建后台线程,管理线程池,结果解析,结果缓存,处理错误,SSL链接等繁多的事务,然而Volley解决了这些问题,让开发者能够聚焦到业务逻辑的实现,并且是更少的代码更少的bug。 上面这张图片是2013年Google IO大会上推出Volley时的图片,从图片中可以看出,Volley适合用来处理“短并且多”的请求,请求就像离弦的满天飞箭一样。注意:Volley并不适合用来做大文件的上传下载操作例如视频流操作
Volley的特点
- 开发高并发的Android应用程序
- 所有的Http请求都运行在后台线程并且管理这些线程
- 灵活的方式运行网络请求
- 提供内置的JSON自动解析
- 可设置请求优先级
- 超时重试策略以及某些Error code作为内部的Server error
- 灵活的Request取消方式
- 图片Memory&Disk缓存,以及批量的图片下载
- 灵活的替换自己的缓存实现
- 可以实现自己的HTTPStack,处理SSL connections,PATCH requests
- 高效的内置协议缓存,处理响应结果的缓存
- 请求过程的追踪,方便调试
集成Volley
Volley简介
-
Volley包含两个主要的类RequestQueue和Request,Volley提供了两个最基础的Requset实现JsonObjectRequest和StringRequest
- RequsetQueue:这是一个分发队列,用来取Requst并在工作线程中执行,如果cache中找到就从cache中获取response,然后将结果回传到UI线程。
- Request:所有的HTTP请求都是由这个类创建的,它封装了用于HTTP请求的主要参数。
- METHOD Type – GET, POST, PUT, DELETE
- URL
- Request data (HTTP Body)
- Successful Response Listener
- Error Listener
初始化RequestQueue
1 |
mVolleyQueue = Volley.newRequestQueue(this); |
通过这个静态方法创建全局的一个请求队列。可以传人Application context参数,它会为你初始化HttpStack,磁盘缓存等。
JsonObjectRequest使用讲解
-
JsonObjectRequest用来处理JSON类型的API。它包括如下几个参数
- HTTP METHOD(GET or POST…)
- A JSON object as request body ( mostly for POST & PUT api’s)
- Success & Error Listener.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
String url = "server_api"; JsonObjectRequest jsonObjRequest = new JsonObjectRequest(Request.Method.GET, url, null, new Response.Listener<JSONObject>() { @Override public void onResponse(JSONObject response) { } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { } }); mVolleyQueue.add(jsonObjRequest); |
StringRequest使用讲解
-
将HTTP Response处理为简单的String,创建StringRequest的参数如下。
- HTTP METHOD(GET or POST…)
- Success & Error Listener.
1 2 3 4 5 6 7 8 9 10 11 |
String url = "server_api"; StringRequest stringRequest = new StringRequest(Request.Method.GET, url, new Response.Listener<String>() { @Override public void onResponse(String response) { } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { } }); mVolleyQueue.add(stringRequest); |
采用Gson实现的GsonRequest
上面提到的Request都是Volley提供的简单的请求类型实现,为了更加方便的处理请求,我们可以自己去实现Request。GSON是用来处理Java对象与JSON转化的类库。通过在请求中加上范型参数,将Response的结果以给定类型返回。下面的代码需要依赖gson.jar。这就实现了Gson与Volley的联合使用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
public class GsonRequest<T> extends Request<T>{ private Gson mGson; public GsonRequest(int method, String url, Class<T> cls, String requestBody, Listener<T> listener, ErrorListener errorListener) { super(method, url, errorListener); mGson = new Gson(); } @Override protected Response<T> parseNetworkResponse(NetworkResponse response) { try { String jsonString = new String(response.data, HttpHeaderParser.parseCharset(response.headers)); T parsedGSON = mGson.fromJson(jsonString, mJavaClass); return Response.success(parsedGSON, HttpHeaderParser.parseCacheHeaders(response)); } catch (UnsupportedEncodingException e) { return Response.error(new ParseError(e)); } catch (JsonSyntaxException je) { return Response.error(new ParseError(je)); } } } |
使用GsonRequest
1 2 3 4 5 6 7 8 9 10 11 12 |
gsonObjRequest = new GsonRequest<Pepople>(Request.Method.GET, url, FlickrResponsePhotos.class, null, new Response.Listener<Pepople>() { @Override public void onResponse(Pepople response) { } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { } }); mVolleyQueue.add(gsonObjRequest); |
Volley图片下载
-
在应用程序开发中图片下载是非常常见的操作,Volley提供了不同的图片下载方式。Volley也提供了透明的图片缓存,也可以灵活的使用自己的图片缓存。
- ImageRequest 和其他的Requst类型一样,它以URL作为参数然后返回Bitmap对象到主线程。
- ImageDownloader 处理图片加载和图片缓存,ImageView和ImageListener作为传人参数。缓存包括MemoryCache和DiskCache。Volley提供的DiskCache是实现的DiskBasedCache。如果需要给ImageDownloader提供自己的cache,需要实现ImageCache接口。
- NetworkImageView 他是ImageView的子类,用来自动下载指定URL的图片,并且自动取消已经回收的请求。开发者可以不用管理ImageRequest的生命周期。
1 2 3 4 5 6 7 8 9 10 11 12 |
ImageRequest imgRequest = new ImageRequest(URL, new Response.Listener<Bitmap>() { @Override public void onResponse(Bitmap response) { mImageView.setImageBitmap(response); } }, 0, 0, Bitmap.Config.ARGB_8888, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { mImageView.setImageResource(R.drawable.error); } }); mVolleyQueue.add(imgRequest); |
1 2 3 4 5 6 7 8 9 10 |
int max_cache_size = 1000000; mImageLoader = new ImageLoader(mVolleyQueue, new DiskBitmapCache(getCacheDir(),max_cache_size)); //Memorycache is always faster than DiskCache. Check it our for yourself. //mImageLoader = new ImageLoader(mVolleyQueue, new BitmapCache(max_cache_size)); mImageLoader.get(URL, ImageLoader.getImageListener(mImageView, R.drawable.flickr, android.R.drawable.ic_dialog_alert, //根据自定义图片宽高来缩放图片 50,50); |
1 |
mNetworkImageView.setImageUrl(testUrlToDownloadImage1, mImageLoader); |
1 2 3 4 5 6 7 8 9 10 11 12 |
RequestFuture<String> future = RequestFuture.newFuture(); StringRequest request = new StringRequest("http://vjson.com", future, future); mRequestQueue.addRequest(request); try { String result = future.get(); //future.get(timeout, unit) Log.d(MainActivity.class.getSimpleName(), result); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } |
Volley添加Headers
-
默认情况下Volley的请求添加Content-Type参数。
- JsonRequest:application/json
- StringRequest: application/x-www-form-urlencoded
- Request: application/x-www-form-urlencoded
- 如果需要改变默认行为,就需要重写getBodyContentType方法
- 如果需要添加额外的请求头,就需要继承Requst然后实现getHeaders方法
1 2 3 4 5 6 7 8 9 10 11 |
public class MyStringRequest extends StringRequest{ private Map<String, String> headers = new HashMap<String, String>(); @Override public Map<String, String> getHeaders() throws AuthFailureError { return headers; } public void setHeader(String title, String content) { headers.put(title, content); } } |
Volley取消请求
Volley可以很灵活的取消请求,可以通过TAG name。当Activity的生命周期方法onStop()调用时,记得取消所有不必要的请求。
1 2 3 4 5 |
request.cancel(); for( Request<T> req : mRequestList) { req.cancel(); } volleyQueue.cancelAll(Object); |
Set Priority to Volley’s Request
Volley支持给请求设置优先级,通常ImageRequest被设置成LOW priority,像StringRequst和JsonRequest这些被设置成NORMAL priority。可以更具自己的需求改变不同请求的优先级,可以选择重写Request中priority的访问方法。或者在外部直接设置优先级
1 2 3 4 5 6 7 8 9 10 11 12 |
Priority priority; public void setPriority(Priority priority) { this.priority = priority; } public Priority getPriority() { if( this.priority != null) { return priority; } else { return Priority.NORMAL; } } |
1 |
request.setPriority(Priority.HIGH); |
Volley Retry Policy
-
Volley提供了非常方便的超时请求重试策略。Volley的所有请求默认情况下SocketTimeout和ConnectionTimeout都是5s。
- Timeout:每一个请求的超时时长以毫秒为单位
- Number Of Retries:重试次数
- BackOff Multiplier:后续重试的乘数因子
RetryPolicy是一个重试策略的接口,可以实现这个接口来满足特殊的重试策略。它定义了三个参数如下:
Timeout: 3000 secs, Num of Attempt: 3, Back Off Multiplier: 2
第一次: time = time + (time * Back Off Multiplier );
time = 3000 + 6000 = 9000
Socket Timeout = time; SocketTimeout = 9000
第二次: time = time + (time * Back Off Multiplier );
time = 9000 + 18000 = 27000
Socket Timeout = time; SocketTimeout = 27000
第三次: time = time + (time * Back Off Multiplier );
time = 27000 + 54000 = 91000
Socket Timeout = time;
SocketTimeout = 91000
如果三次重试之后仍然发生Socket Timeout,Volley将抛出一个TimeoutError。
12345 //Set a retry policy in case of SocketTimeout & ConnectionTimeout Exceptions.//Volley does retry for you if you have specified the policy.request.setRetryPolicy(new DefaultRetryPolicy(5000,DefaultRetryPolicy.DEFAULT_MAX_RETRIES,DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
Volley HTTPs
Volley默认不支持HTTPS,所以需要自己提供支持SSL connection的HttpStack。 可以在自己的HttpClient中设置SSL socket factory执行安全的加密请求。下面是一段处理自签名证书类型的SSL请求代码。
1 2 3 4 5 6 7 8 9 10 11 12 |
SslHttpStack implements HtpStack @Override public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders) throws IOException, AuthFailureError { HttpUriRequest httpRequest = createHttpRequest(request, additionalHeaders); SchemeRegistry registry = new SchemeRegistry(); registry.register(new Scheme("http", new PlainSocketFactory(), 80)); registry.register(new Scheme("https", new EasySSLSocketFactory(mIsConnectingToYourServer), 443)); ThreadSafeClientConnManager manager = new ThreadSafeClientConnManager(httpParams, registry); HttpClient httpClient = new DefaultHttpClient(manager, httpParams); } |
在Logcat中开启Volley日志
- adb shell
- setprop log.tag.Volley VERBOSE logcat 配置之后就可以看到Volley的日志了,从这个日志中可以跟踪请求的整个生命周期。
D/Volley (24482): [1] MarkerLog.finish: (7067 ms) [X] http://vjson.com NORMAL 1
D/Volley (24482): [1] MarkerLog.finish: (+0 ) [ 1] add-to-queue
D/Volley (24482): [1] MarkerLog.finish: (+6 ) [9624] cache-queue-take
D/Volley (24482): [1] MarkerLog.finish: (+7 ) [9624] cache-hit-expired
D/Volley (24482): [1] MarkerLog.finish: (+0 ) [9625] network-queue-take
D/Volley (24482): [1] MarkerLog.finish: (+5726) [9625] network-http-complete
D/Volley (24482): [1] MarkerLog.finish: (+1158) [9625] network-parse-complete
D/Volley (24482): [1] MarkerLog.finish: (+169 ) [9625] network-cache-written
D/Volley (24482): [1] MarkerLog.finish: (+1 ) [9625] post-response
**D/Volley (24482): [1] MarkerLog.finish: (+0 ) [ 1] canceled-at-delivery**
总结
这里只是简单的介绍Volley的使用方法,并没有对Volley源码进行分析,后续的文章中将会分析Volley的源码。