文档结构  
翻译进度:已翻译     翻译赏金:0 元 (?)    ¥ 我要打赏

本文已更新2016年12月21日。具体更新为:添加新内容,更新已弃用的代码,并添加了对图像加载部分。

在Android中使用Volley进行网络连接

从移动技术产生到现在,网络一直存在着。Android没有不同,改变的是网络操作的处理方式。网络库(如Volley)的关注的重点是网络操作的自动化。

先前网络调用是在主线程中执行的,直到HoneyComb以及随后的Android版本,网络请求与主线程异步执行。要进行网络调用,开发人员需要在与应用程序主线程不同的线程中实现Asynctask,否则将抛出NetworkOnMainThreadException异常。

第 1 段(可获 1.44 积分)

Volley简短概述

Volley是一个管理网络请求的Android网络库。它捆绑了您需要的最重要功能,例如在一个更易于使用的包中访问JSON API,加载图像和字符串请求。

通过使用Volley进行网络操作,您可以避免使用HttpURLConnection来处理网络连接。另一个原因是异步性。 Volley自身处理异步,不需要手动创建Asynctask。

基于documentation,Volley执行的每个网络操作的核心是RequestQueue。 可以通过创建一个RequestQueue对象并向它传递Request对象来使用Volley。 RequestQueue管理用于运行网络操作、读取和写入缓存以及解析响应的工作线程。

第 2 段(可获 1.44 积分)

Volley提供了丰富的特性,如文档所述:

  1. 网络请求自动调度
  2. 多并发
  3. 缓存
  4. 请求优先级
  5. 取消进行中的请求

这些是Volley库的核心优点,也是本文讨论的核心。

导入Volley库,添加权限

要使用Volley,必须首先配置你的Android工程
创建新工程,打开 build.gradle(子项目: app) ,添加如下依赖

dependencies {
    //...

    compile 'com.android.volley:volley:1.0.0'
}
第 3 段(可获 0.89 积分)

在AndroidManifest.xml 添加网络请求权限.

<uses-permission android:name="android.permission.INTERNET" />

标准网络请求

如上所述,Volley 网络处理的核心是RequestQueue。每次请求都是通过向RequestQueue 传递Request 对象。有三种类型的请求: JSON 请求、 图像请求和简单请求。下面将介绍每种不同的请求并提供代码例子。

下面,在 MainActivity的 onCreate() 方法中初始化 RequestQueue。

第 4 段(可获 0.85 积分)
    RequestQueue requestQueue;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        //...
        requestQueue = Volley.newRequestQueue(this); // 'this' is the Context

    }

JSON请求

Volley有对JSONObject和JSONArray的请求。 JSONRequest的结构和Volley中包含的大多数请求类使用如下所示的构造函数。

JsonObjectRequest request=new JsonObjectRequest(RequestMethod, URL, null,  new ResponseListener(), new ErrorListener());

传递给构造函数的参数:

  • RequestMethod (GET, POST, PUT, DELETE等)
  • URL: 被请求对象的URL资源链接;
  • JSONObject: 与请求一起发送的可选对象,如果没有,则为null;
  • ResponseListener: 响应侦听器,其回调方法将包含响应内容;
  • ErrorListener: Response.ErrorListener,其回调方法将包含请求异常信息。
第 5 段(可获 0.96 积分)

下面的代码段,分别完整实现了JsonObjectRequest和JsonArrayRequest.

        /*Json请求*/
   String url = "https://json_url/";
   JsonObjectRequest jsonObjectRequest = 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) {

               }
           });
   //将请求添加到队列
   requestQueue.add(jsonObjectRequest);

   JsonArrayRequest jsonArrayRequest = new JsonArrayRequest(Request.Method.GET, url, null,
           new Response.Listener<JSONArray>() {
               @Override
               public void onResponse(JSONArray response) {

               }
           },
           new Response.ErrorListener() {
               @Override
               public void onErrorResponse(VolleyError error) {

               }
           });
   //将请求添加到队列
   requestQueue.add(jsonArrayRequest);
第 6 段(可获 0.15 积分)

现在我已经展示了如何在Android中接收JSON数据,让我们看看如何使用Volley发送数据。

请求的格式与接收JSON数据的格式相同,但必须指定一个JSONObject,其中包含用于将数据从客户端发送到服务器端的请求和请求标头。

    /*Post data*/
    Map<String, String> jsonParams = new HashMap<String, String>();

    jsonParams.put("email", "user@gmail.com");
    jsonParams.put("username", "user");
    jsonParams.put("password", "pass");

    JsonObjectRequest postRequest = new JsonObjectRequest( Request.Method.POST, URL,

          new JSONObject(jsonParams),
            new Response.Listener<JSONObject>() {
                @Override
                public void onResponse(JSONObject response) {
                }
            },
            new Response.ErrorListener() {
                @Override
                public void onErrorResponse(VolleyError error) {
                  // Handle Error
                }
            }) {
        @Override
        public Map<String, String> getHeaders() throws AuthFailureError {
            HashMap<String, String> headers = new HashMap<String, String>();
            headers.put("Content-Type", "application/json; charset=utf-8");
            headers.put("User-agent", System.getProperty("http.agent"));
            return headers;
        }
    };
    requestQueue.add(postRequest);
第 7 段(可获 0.69 积分)

请注意,请求头可能需要根据开发用例进行更改。

字符串请求

此类型的请求用于以字符串形式从服务器检索数据。

   /*String Request*/
   String url = "https://string_url/";
   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) {

               }
           });
   //add request to queue
   requestQueue.add(stringRequest);
第 8 段(可获 0.4 积分)

StringRequest的结构包含请求方法(POST或GET),字符串资源的URL,Response.Listener和Response.ErrorListener。几乎和JsonRequest一样。

图像请求

Volley提供了几种在Android中加载图片的方法。我将一一解释他们的差异,并提供一些代码示例。

ImageRequest

ImageRequest是一种从给定网址加载图片的方法。该网络调用的结构类似于前面描述的其他请求。

第 9 段(可获 1.03 积分)

下面的代码是一个ImageRequest将图像加载到ImageView的示例。

   int maxWidth = ...;
   int maxHeight = ...;
   String URL = "http://image_url.png";
   ImageRequest imageRequest = new ImageRequest(URL, new Response.Listener<Bitmap>() {
       @Override
       public void onResponse(Bitmap response) {
           // Assign the response to an ImageView
           ImageView imageView = (ImageView) findViewById(R.id.imageView);
           imageView.setImageBitmap(response);
       }
   }, maxWidth, maxHeight, null);
   //add request to queue
   requestQueue.add(imageRequest);

ImageRequest的结构很简单。它需要图像的URL,一个响应侦听器,其回调方法将返回位图图像(Bitmap),maxWidth和maxHeight,用于解码位图的配置格式,以及用于处理错误的Response.ErrorListener。将请求添加到RequestQueue,Android运行时环境将为你处理其他的事情。

第 10 段(可获 0.86 积分)

ImageLoader

ImageLoader是一个帮助类,用于从远程URL加载和缓存图像。此请求在需要大量的ImageRequest时非常有用。根据文档(documentation)可以了解到,ImageLoader在Volley缓存前提供了一个内存缓存,这对于防止flickering很重要。

NetworkImageView

当图像从网络上加载时,networkimageview是取代ImageView一种有效的方式。

以下代码片段提供了使用Volley的图像加载最后两部分的实现。以下VolleySingleton类是RequestQueue的实现。这个单例类具有内存中LRU缓存的缓存功能。 LruCache设置为存储最多30个元素。

import android.content.Context;
import android.graphics.Bitmap;
import android.support.v4.util.LruCache;
import android.util.Log;

import com.android.volley.RequestQueue;
import com.android.volley.toolbox.ImageLoader;
import com.android.volley.toolbox.Volley;

public class VolleySingleton {
    private static VolleySingleton singletonInstance = null;
    private RequestQueue requestQueue;
    private ImageLoader imageLoader;

    private VolleySingleton(Context context) {
        requestQueue = Volley.newRequestQueue(context);
        imageLoader = new ImageLoader(this.requestQueue, new ImageLoader.ImageCache() {
            private final LruCache<String, Bitmap> lruCache = new LruCache<String, Bitmap>(30);
            //30 -> the maximum number of entries in the cache.

            public void putBitmap(String url, Bitmap bitmap) {
                lruCache.put(url, bitmap);
                Log.d("CachedItems", String.valueOf(lruCache.size()));
            }

            public Bitmap getBitmap(String url) {
                return lruCache.get(url);
            }
        });
    }

    public static VolleySingleton getInstance(Context context) {
        if (singletonInstance == null) {
            singletonInstance = new VolleySingleton(context);
        }
        return singletonInstance;
    }

    public RequestQueue getRequestQueue() {
        return this.requestQueue;
    }

    public ImageLoader getImageLoader() {
        return this.imageLoader;
    }
}
第 11 段(可获 1.31 积分)

现在,VolleySingleton类已设置,让我们将一个图像加载到NetworkImageView中。但首先,在Activity的布局文件中添加一个实例。例子如下:

<com.android.volley.toolbox.NetworkImageView  android:id="@+id/networkImageView" android:layout_width="match_parent" android:layout_height="wrap_content" />

最后,将图像加载到NetworkImageView中。在MainActivity的onCreate()方法中添加下面的代码。

    private ImageLoader imageLoader;
    private NetworkImageView imageView;
    private static final String IMAGE_URL = "https://the_images_url.jpg";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        //...

        imageLoader = VolleySingleton.getInstance(getApplicationContext()).getImageLoader();
        imageView = (NetworkImageView) findViewById(R.id.networkImageView);
        imageView.setImageUrl(IMAGE_URL, imageLoader);

    }
第 12 段(可获 0.51 积分)

为了确保缓存正常工作,我在VolleySingleton类中添加了一个Log语句。运行项目并检查Android Studio日志。每次新的图像被缓存时,设备打印出多个缓存条目信息。

请求优先级

处理网络请求意味着需要优先处理某些请求以及需要多快的响应,因为网络是实时操作的。

Volley以先进先出的顺序处理从较高优先级到较低优先级的请求。因为没有setPriority()方法,因此要优先处理请求,需要额外的工作。

第 13 段(可获 1.13 积分)

下面是一个可以进行优先级请求的自定义JsonObjectRequest类的示例。这个类的重点是重写的getPriority()方法。当请求被添加到队列中时,此方法将返回由setPriority()分配给它的优先级或类中分配的Priority.HIGH,但它不会在此类之外搜索优先级。

The same structure applies to all the other request types.

public class CustomPriorityRequest extends JsonObjectRequest {

    Priority priority = Priority.HIGH;

    public CustomPriorityRequest(int method, String url, JSONObject jsonRequest, Response.Listener<JSONObject> listener, Response.ErrorListener errorListener) {
        super(method, url, jsonRequest, listener, errorListener);
    }

    public CustomPriorityRequest(String url, JSONObject jsonRequest, Response.Listener<JSONObject> listener, Response.ErrorListener errorListener) {
        super(url, jsonRequest, listener, errorListener);
    }

    @Override
    public Priority getPriority() {
        return priority;
    }

    public void setPriority(Priority p){
        priority = p;
    }
}
第 14 段(可获 0.86 积分)

使用此新类发出请求与标准请求相同。您可以在将请求添加到队列之前设置请求优先级。

   CustomPriorityRequest customPriorityRequest = new CustomPriorityRequest(
           Request.Method.GET, URL, null,
           new Response.Listener<JSONObject>(),
           new Response.ErrorListener());

   customPriorityRequest.setPriority(Request.Priority.IMMEDIATE);
   requestQueue.add(customPriorityRequest);

一些可用的优先级是:Priority.LOW,Priority.NORMAL,Priority.HIGH和Priority.IMMEDIATE。

第 15 段(可获 0.53 积分)

取消请求

Volley的另一个有用的工具是能够取消请求。当用户关闭应用程序或执行导致不需要Volley请求的操作时,取消请求很有用。在队列中执行没必要的请求是没有意义的,因此我们在onStop()方法中取消它们。

在Volley中取消请求的最简单方法是向请求中添加一个标记,当排队的请求需要取消时,调用cancelAll()方法。这将取消使用该特定标记指定的所有请求。

request.setTag("TAG");

requestQueue.cancelAll("TAG");

一旦cancelAll()从主线程执行,剩余的响应将不会被传递。

第 16 段(可获 1.36 积分)

文章评论