Android Volley

时间:2020-02-23 14:29:23  来源:igfitidea点击:

在本教程中,我们将详细讨论应用程序中的一个重要网络库,即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的引入,在依赖项中,关键字compileimplementation取代。
两者可以互换使用。

下面列出了凌空基础程序。

  • 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()"。