Android Volley
在本教程中,我们将详细讨论应用程序中的一个重要网络库,即Android Volley。
Android Volley库由Google开发。
谷歌I/O 2013首次展示了它。
让我们来看看它的功能!
Android Volley
网络是当今大多数Android应用程序中的关键组件。
当我们有太多网络请求需要处理时,使用AsyncTask可能不是最佳选择。
AsyncTask无法按顺序排列并行/多个请求的优先级。
此外,他们还有很多样板代码。
这是Android Volley库随手提供的工具。
它具有一些强大的功能,并且比AsyncTask快很多。
Android Volley Library的优点
自动调度所有网络请求。
多个并发网络连接。
请求排队和优先级。
缓存响应。
它支持基于内存和磁盘的缓存。取消一个或者多个请求。
对字符串,图像,JSONObject和JSONArray请求的内置支持。
能够创建自定义请求。
内置的NetworkImageView小部件可轻松从URL加载图像。
支持重试请求。
强大的调试和跟踪工具可捕获错误。
Android Volley入门
要将Volley集成到您的Android Studio项目中,您需要在build.gradle文件中添加以下依赖项:
compile 'com.android.volley:volley:1.0.0'
与Retrofit不同,Volley Library的大小要小得多,Retrofit需要像OkHttp,Picasso这样的一堆库才能实现完整的功能。
注意:随着Android Studio 3.0 IDE的引入,在依赖项中,关键字compile
被implementation
取代。
两者可以互换使用。
下面列出了凌空基础程序。
RequestQueue
请求
- 响应
Android Volley RequestQueue
这是Volley的基本构建块。
名字足以说明问题。
RequestQueue用于对所有请求进行排队并处理响应。
而且,除了读写缓存外,它还负责管理并行请求的工作线程。
RequestQueue以FIFO方式(先进先出)工作。
一次它可以同时处理四个请求。
在类中以以下方式实例化RequestQueue。
RequestQueue requestQueue = Volley.newRequestQueue(this);
" this"是指上下文。
它可以是活动或者应用程序的上下文。
上面的代码使用默认的一组参数初始化RequestQueue。
我们可以使用我们自己的一组参数来初始化RequestQueue,如下所示。
RequestQueue mRequestQueue; //Instantiate the cache Cache cache = new DiskBasedCache(getCacheDir(), 1024 * 1024); //1MB cap //Set up the network to use HttpURLConnection as the HTTP client. Network network = new BasicNetwork(new HurlStack()); //Instantiate the RequestQueue with the cache and network. mRequestQueue = new RequestQueue(cache, network); //Start the queue mRequestQueue.start();
我们已经使用自定义参数初始化了自己的Cache和Network实例。
调用方法" mRequestQueue.stop()"以停止将处理请求的队列。
Android Volley请求
构建请求实例以定义网络请求。
这些用于支持GET和POST请求。
请求类充当可扩展以定义自定义请求的基类。
排球提供以下内置的请求类型:
- 字符串请求
- JsonObjectRequest
- JsonArrayRequest
- 图片请求
Android Volley StringRequest
当您希望响应以字符串形式返回时,使用StringRequest。
然后,您可以根据需要使用Gson或者JSON解析响应。
StringRequest具有两种形式的构造函数,如下图所示。
我们将在这里讨论第一个构造函数。
StringRequest(int method, String url, Response.Listener<String> listener, Response.ErrorListener errorListener)
方法:需要GET,POST,PUT,DELETE之间的参数。
url:获取响应的URl。
监听器:监听成功响应。
我们需要在这里实现并重写以下方法。errorListener:侦听错误响应。
我们需要在这里实现以下方法。
下面给出了字符串请求的示例代码片段。
@Override public void onResponse(String response){ //response parameter is of the same type as defined in the constructor. }
响应或者错误将传递到我们在上面的请求中定义的onResponse/onErrorResponse类。
queue.add(stringRequest);用于将请求添加到RequestQueue。
上面编写的代码段可以简化以提高可读性。
@Override public void onErrorResponse(VolleyError error){ //handle your error here. We'll look at }
现在构造函数看起来好多了。
为了在请求主体中发送参数,我们需要重写请求类的getParams()或者getBody()方法。
另外,我们也可以覆盖getHeaders()和getBodyContentType()方法来分别指定标题和内容类型格式。
getHeaders()对于身份验证很有用。
为了从第一个参数覆盖请求方法类型,实现了" getMethod()"。
下面给出上述方法的框架代码构造函数。
RequestQueue queue = Volley.newRequestQueue(this); StringRequest stringRequest = new StringRequest(Request.Method.GET, url, new Response.Listener<String>() { @Override public void onResponse(String response) { VolleyLog.wtf(response, "utf-8"); } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { VolleyLog.wtf(error.getMessage(), "utf-8"); } }); queue.add(stringRequest);
参数和标头分别在getParams()和getHeaders()方法中指定为键-值对。
注意:当请求类型为GET时,将忽略getParams()
方法。
因此,要传递参数,我们需要将其串联在URL字符串中,如下所示。
Response.ErrorListener errorListener = new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { VolleyLog.wtf(error.getMessage(), "utf-8"); } }; Response.Listener<String> responseListener = new Response.Listener<String>() { @Override public void onResponse(String response) { VolleyLog.wtf(response); } }; StringRequest stringRequest = new StringRequest(Request.Method.GET, url, responseListener, errorListener);
%1 $s用于第一个参数。
第二个,第三个参数的为'%2 $s','%3 $s'等。
Android Volley JsonObjectRequest
JsonObjectRequest用于从服务器发送和接收JSONObject。
它扩展了类JsonRequest。
下面给出了两种形式的构造函数。
我们将在这里查看第二个构造函数。
StringRequest stringRequest = new StringRequest(Request.Method.GET, url, responseListener, errorListener){ @Override public Map getParams() { Map params = new HashMap(); params.put("key", "value"); return params; } @Override public byte[] getBody() throws AuthFailureError { String requestBody = ""; //The request body goes in here. try { return requestBody.getBytes("utf-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); VolleyLog.wtf("Unsupported Encoding while trying to get the bytes of %s using %s", requestBody, "utf-8"); return null; } } @Override public Map getHeaders() throws AuthFailureError { HashMap headers = new HashMap(); headers.put("Content-Type", "application/x-www-form-urlencoded; charset=utf-8"); String credentials = "sample:theitroad@123"; String auth = "Basic " + Base64.encodeToString(credentials.getBytes(), Base64.NO_WRAP); headers.put("Authorization",auth); //authentication return headers; } @Override public String getBodyContentType() { return "application/x-www-form-urlencoded; charset=utf-8"; } @Override public int getMethod() { return Method.POST; } };
可以将可选的JSONObject作为请求主体传递给构造函数的第二个参数。
我们现在将其设置为null。
除了StringStringRequest之外,JsonObjectRequest可以覆盖同一组方法(getHeaders(),getBodyContentType(),getBody(),getMethod()),除了getParams()之外。
JsonObjectRequest用于将JSONObject与请求一起传递。
因此getParams()
被忽略。
在JsonObjectRequest中不需要覆盖getBody()
,因为传递JSONObject作为第二个参数会隐式地执行相同的操作。
如果最终覆盖了getBody(),则构造函数中传递的第二个参数将被忽略。
由于上述构造函数中未定义请求类型,因此请求会自动从网址中识别方法(GET,POST,PUT或者DELETE)。
为了明确指定方法类型,我们可以重写getMethod()
。
String BASE_URL = "https://reqres.in"; String url = String.format(BASE_URL + "/api/users?page=%1$s", "2");
Android Volley JsonArrayRequest
JsonArrayRequest用于向服务器发送和从服务器检索JSONArray。
它扩展了JsonRequest类并以与JsonObjectRequest类相同的方式起作用。
JSONArrayRequest无法处理返回JSONObject的请求。
以下是构造函数的两种形式。
我们来看第二个构造函数。
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(url, null, new Response.Listener<JSONObject>() { @Override public void onResponse(JSONObject response) { VolleyLog.wtf(response.toString()); } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { VolleyLog.wtf(error.getMessage(), "utf-8"); } }); queue.add(jsonObjectRequest)
Android Volley ImageRequest
使用ImageRequest是从URL提取图像的经典和标准方法。
ImageRequest返回一个位图对象,该对象最终可以显示在ImageView中。
以下是该类中存在的两个构造函数。
让我们使用第二个构造函数,因为第一个构造函数现在已弃用。
除了url,响应和错误侦听器之外,构造函数还需要位图的宽度,高度,scaleType和Config值。
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(url, null, responseListener, errorListener){ @Override public int getMethod() { return Method.POST; //This specifies the Method type to POST explicitly. } @Override public byte[] getBody() { //Building the response body here would ignore the JSONObject passed in the second parameter. } };
RequestQueue具有一个RequestFinishedListener。
每当队列中的请求完成时,都会触发侦听器。
JsonArrayRequest jsonArrayRequest = new JsonArrayRequest(Request.Method.POST, url, null, new Response.Listener<JSONArray>() { @Override public void onResponse(JSONArray response) { } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { VolleyLog.wtf(error.getMessage(), "utf-8"); } });
Android Volley错误处理
如上所述,onErrorResponse()
传递了VolleyError的一个实例。
以下是实例中可能返回的错误的主要类型。
AuthFailureError:身份验证失败时。
NetworkError:服务器错误,DNS问题等。
NoConnectionError:没有互联网连接时。
ParseError:JSON响应格式错误时,通常在JsonObjectRequest或者JsonArrayRequest中返回。
ServerError:服务器以错误状态代码(401、500等)响应
TimeoutError:发生请求超时时。
排球的默认超时为2.5秒。
Android Volley取消请求
Volley有一个强大的API用于取消请求。
在需要销毁活动的情况下,取消请求很重要。
使用标签可以取消请求。
RequestQueue queue = Volley.newRequestQueue(this); ImageRequest imageRequest = new ImageRequest(IMAGE_URL, new Response.Listener<Bitmap>() { @Override public void onResponse(Bitmap response) { if (response != null) { imageView.setImageBitmap(response); } } }, 200, 200, ImageView.ScaleType.CENTER_CROP, Bitmap.Config.ARGB_8888, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { VolleyLog.wtf(error.getMessage(), "utf-8"); } }); queue.add(imageRequest);
Android Volley优先处理请求
可以为RequestQueue中存在的每个请求设置优先级。
这样做,RequestQueue将基于优先级而不是FIFO运行请求。
可以通过重写构造函数中的方法getPriority()来分配优先级。
以下是可能的状态:
Priority.LOW:用于加载图像。
Priority.NORMAL:默认值。
Priority.HIGH:用于加载文本。
Priority.IMMEDIATE:用于登录/注销之类的地方。
以下代码段为请求分配优先级。
queue.addRequestFinishedListener(new RequestQueue.RequestFinishedListener<Object>() { @Override public void onRequestFinished(Request<Object> request) { try { if (request.getCacheEntry() != null) { String cacheValue = new String(request.getCacheEntry().data, "UTF-8"); Log.d(TAG, request.getCacheKey() + " " + cacheValue); } } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } });
Android Volley缓存
默认情况下,为上述请求类型启用缓存。
响应数据通常以字节数组的形式存储
禁用缓存
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(url, null, responseListener, errorListener); jsonObjectRequest.setTag("Sample"); JsonObjectRequest jsonObjectRequest2 = new JsonObjectRequest(url_2, null, responseListener, errorListener); jsonObjectRequest2.setTag("No sample"); queue.add(jsonObjectRequest); queue.add(jsonObjectRequest2); queue.cancelAll("Sample"); //Cancels all requests with tag "Sample" present in the RequestQueue. //Alternative way.... queue.cancelAll(new RequestQueue.RequestFilter() { @Override public boolean apply(Request<?> request) { return request.getTag().equals("Sample"); //requests with the condition true are cancelled. } });
访问缓存
RequestQueue queue = Volley.newRequestQueue(this); Response.Listener<JSONObject> jsonResponseListener = new Response.Listener<JSONObject>() { @Override public void onResponse(JSONObject response) { } }; Response.Listener<String> stringResponseListener = new Response.Listener<String>() { @Override public void onResponse(String response) { } }; Response.Listener imageResponseListener = new Response.Listener() { @Override public void onResponse(Bitmap response) { } }; Response.ErrorListener errorListener = new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { VolleyLog.wtf(error.getMessage(), "utf-8"); } }; StringRequest stringRequest = new StringRequest(Request.Method.GET, url, stringResponseListener, errorListener){ @Override public Priority getPriority() { return Priority.IMMEDIATE; }}; JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(url, null, jsonResponseListener, errorListener){ @Override public Priority getPriority() { return Priority.HIGH; }};; ImageRequest imageRequest = new ImageRequest(IMAGE_URL, imageResponseListener, 200, 200, ImageView.ScaleType.CENTER_CROP, Bitmap.Config.ARGB_8888, errorListener){ @Override public Priority getPriority() { return Priority.LOW; }};; queue.add(imageRequest); queue.add(jsonObjectRequest); queue.add(stringRequest); //Order of requests run : stringRequest > jsonRequest > imageRequest
清除缓存
stringRequest.setShouldCache(false)
使缓存无效:使缓存无效将显示缓存的数据,直到返回新的响应为止。
该响应将覆盖当前的缓存。
String cacheValue = new String(stringRequest.getCacheEntry().data, "UTF-8"); //Accessing from the RequestQueue String cacheValue = new String(queue.getCache().get(url).data, "UTF-8"); //The Request URL is stored in the cache key ... String url = request.getCacheKey(); //Check other details in the cache. stringRequest.getCacheEntry().isExpired() //checks if the cache is expired or not. stringRequest.getCacheEntry().lastModified
Android Volley ImageLoader和NetworkImageView
我们之前曾使用ImageRequest来从响应中检索图像位图。
Volley为我们提供了NetworkImageView小部件,该小部件可直接从URL加载图像。
此外,它允许我们设置默认的占位符以及可绘制的错误。
ImageLoader负责使用BitmapLruCache()加载图像。
queue.getCache().remove(url); //removes cache for the specific url. //clear all cache.... queue.getCache().clear();
setImageFromUrl()方法直接将从网址返回的图像设置到NetworkImageView实例上。
我们需要在此方法中传递URL和ImageLoader实例以获取图像。
queue.getCache().invalidate(url, true);
注意:要排除故障并记录调试跟踪,请在代码中设置以下行。
<com.android.volley.toolbox.NetworkImageView android:id="@+id/networkImageView" android:layout_width="100dp" android:layout_height="100dp"
我们也可以通过扩展Request <T>来创建自己的自定义请求。
需要重写两个抽象方法" parseNetworkResponse()"和" deliverResponse()"。