打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
Volley介绍

Volley是由Google开发的网络请求库,该库在2013年Google I / O大会上推出的。 由于在Android SDK中缺少在不干扰用户体验的情况下进行网络请求的库,因此开发了Volley库。

在发布Volley库之前,Android程序员如果想在客户端和后台之间开发RESTFul系统,只能使用类  java.net.HttpURLConnection 和类Apache  org.apache.http.client

就算不考虑使用这两个类时出现的错误,除了简单的HTTP事务之外,所有事情都必须从头开始。  如果想缓存图像或优先处理某个请求,则那么这些都必须从头开始。

幸运的是,现在有了Volley库,专门为这些需求而量身打造。

1.为什么使用Volley?

避免使用  HttpUrlConnection 和HttpClient

在较低版本的API(主要是Gingerbread和Froyo)中,  HttpUrlConnectionHttpClient远未完美。 有一些已知错误和bug从未修复过。 此外,  在最后一次API更新(API 22)中HttpClient被弃用,这意味着它将不再被维护,并且在将来的版本中可能被删除。

这些理由足够你决定切换到更可靠的处理网络请求的方式来。

也要避免  AsyncTask

自从引入Honeycomb(API 11)系统以来,网络操作必须在与主线程不同的单独线程上执行。 这一重大变化导致了大量使用 AsyncTask<Params, Progress, Result> 规范。

要使用AsyncTask,首先定义一些准备动作,如在onPreExecute中定义上下文。 然后使用doInBackground 方法执行异步任务。 最后,在onPostExecute中处理结果。 这是非常简单的,比实现服务更容易,并附带了大量的示例和文档。

然而,主要的问题是串行化调用。 使用AsyncTask类,您无法确定首先进行哪个请求,哪一个必须等待。 一切都是先进先出。

例如,当您必须加载附加缩略图列表时,问题就出现了。 当用户向下滚动并预期新的结果时,您不能告诉您的activity,首先加载下一页的JSON,然后再加载上一个页的图像。 这可能会在诸如Facebook或Twitter的应用程序中成为严重的用户体验问题,因为这类APP的新item列表比与其关联的缩略图更重要。

Volley旨在通过引入强大的取消API来解决这个问题。 执行调用时不再需要在onPostExecute中检查activity是否被销毁。 这有助于避免不必要的 NullPointerException异常。

它更快了

前段时间,Google+小组对Android上可用于进行网络请求的各种不同方法进行了一系列的性能测试。 当在RESTful应用程序中使用时,Volley的得分比其他库的分数高出十倍。

它缓存一切

Volley自动缓存请求,这是真正的“拯救生命”。 让我们回到前面给出的例子。 您有一个item列表 - 一个JSON数组,而且每个item都有一个描述和与之关联的缩略图。 现在想想如果用户旋转屏幕会发生什么:activity被摧毁,列表被再次加载,图像也是被再次加载。 这将导致资源浪费和糟糕的用户体验。

Volley被证明能解决这个问题。 它记住以前的调用,并处理activity的销毁和重建。 它缓存所有的东西,而你不必担心它。

小元数据操作

Volley非常适合小调用,例如JSON对象,列表部分,所选item的详细信息等。 它为RESTful应用程序设计,因此能给出了最好的结果。

然而,当用于流式操作和大量下载时,Volley表现不佳。 与一般思维相反,Volley的名字不是来自运动词典。 这是作为重复突发的调用,并且分组在一起的。 这就是为什么这个库不适合这种场合。

2.Under the Hood

Volley在三个不同层次上工作,每个层次    都在自己的线程上运行。

主线程

在主线程上,与AsyncTask 规范一致,  只允许触发请求并处理其响应。 没有更多了,也没有更少了。

主要的后果是您可以忽略doInBackground 方法中发生的一切  。 Volley自动管理您以前需要关心的HTTP事务和捕获的网络错误。

缓存和网络线程

当你向队列添加一个请求时,会发生几件事情。 首先,Volley检查请求是否可以从缓存获取服务。 如果可以,缓存的响应被读取、解析和传递。 否则请求被传递给网络线程。

在网络线程上,一系列线程的循环不断工作。 第一个可用的网络线程对请求进行排队、进行HTTP请求、解析响应、写入缓存。 最后,它将解析的响应重新发送回您的主线程,在主线程中的监听器正在等待处理结果。

3. 入门

步骤1:导入Volley

Volley设置并不方便。 看起来好像没有官方的Maven库可用,这是非常令人困惑的。 你必须依靠官方的源代码。 您可以通过多种方式之一导入Volley。

首先,从其存储库下载Volley源代码。 如果你有信心这样做,这个Git  命令可以为你做所有的工作:

1
git clone https://android.googlesource.com/platform/frameworks/volley

直到几个星期前,您可以使用ant命令行(android update project -p .  然后  ant jar)将所有内容包装起来,并使用简单的compile files('libs/volley.jar')在Android Studio项目中导入JAR库  。

最近,Google已将Volley更新为Android Studio构建样式,从而难以创建独立的JAR包。 您仍然可以这样做,但只能使用旧版本的库。 我个人不鼓励你使用这个选项,尽管看起来最快。

您应该以经典的方式设置Volley ,即通过将源代码导入为module。 在Android Studio中,打开项目后,选择“ 文件”>“新建模块”,然后选择“ 导入现有项目”。 选择刚刚下载源代码的目录并确认。 名为Volley的文件夹将显示在您的项目结构中。 Android Studio自动更新您的  settings.gradle文件以包含Volley模块,因此您只需要将compile project(':volley')添加到依赖关系即可完成。

有第三种方式。 您可以添加build.gradle文件的依赖关系部分:

1
compile 'com.mcxiaoke.volley:library-aar:1.0.15'

它是官方Google存储库的镜像副本,经常同步和更新。 这可能是最简单和最快速的入门方式了。 但是,请注意,这是一个非官方的 Maven存储库,不能保证,也不由Google支持。

在我看来,投入更多的时间导入官方源代码还是比较好。 这样,您可以轻松地跳转到原来的定义和实现,以便在有疑问的情况下,您可以随时依靠官方的Volley源代码,甚至可以根据需要进行更改。

步骤2:使用Volley

Volley大多数情况下只用两个类工作,  RequestQueueRequest。 您首先创建一个  RequestQueue,它管理工作线程并将解析的结果传递回主线程。 然后,给RequestQueue传递一个或多个  Request 对象。

Request构造函数总是把方法类型(GET,POST等)、资源的URL和事件侦听器作为参数。 然后,根据请求的类型,它可能会要求一些更多的变量。

在下面的例子中,我通过调用一个Volley方法 Volley.newRequestQueue来创建一个RequestQueue对象。 这将使用Volley定义的默认值设置RequestQueue对象。

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
String url = "http://httpbin.org/html";
// Request a string response
StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
            new Response.Listener<String>() {
    @Override
    public void onResponse(String response) {
        // Result handling
        System.out.println(response.substring(0,100));
    }
}, new Response.ErrorListener() {
    @Override
    public void onErrorResponse(VolleyError error) {
         
        // Error handling
        System.out.println("Something went wrong!");
        error.printStackTrace();
    }
});
// Add the request to the queue
Volley.newRequestQueue(this).add(stringRequest);

正如你所看到的,这是非常简单的。 您创建请求并将其添加到请求队列。 你完成了。

请注意,监听器的语法类似于AsyncTask.onPostExecute,只是它变成了onResponse。 这不是巧合。 使用Volley的开发人员有意使库的API与AsyncTask 方法类似 。 这使得从使用AsyncTask切换到Volley更容易。

如果您必须在多个activity中进行多个请求,则应避免使用上述方法Volley.newRequestQueue.add。 最好是实例化一个共享的请求队列,并在您的项目中使用它:

1
MySingletonClass.getInstance().getRequestQueue().add(myRequest);

我们将在本系列的下一个教程中专门开发这样的东西。

4.  胜利在望

处理标准要求

Volley可以实现三种非常常见的请求类型:

  • StringRequest
  • ImageRequest
  • JsonRequest

这些类中的每一个都继承了我们之前使用的Result类。 我们已经在前面的例子看过StringRequest了。 让我们来看看JsonRequest工作原理。

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
JsonObjectRequest jsonRequest = new JsonObjectRequest
        (Request.Method.GET, url, null, new Response.Listener<JSONObject>() {
            @Override
            public void onResponse(JSONObject response) {
                // the response is already constructed as a JSONObject!
                try {
                    response = response.getJSONObject("args");
                    String site = response.getString("site"),
                            network = response.getString("network");
                    System.out.println("Site: "+site+"\nNetwork: "+network);
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                error.printStackTrace();
            }
        });
Volley.newRequestQueue(this).add(jsonRequest);

美丽。 不是吗? 您可以看到,结果类型已设置为JSONObject。 你也可以请求一个JSONArray如果你想要,使用JsonArrayRequest而不是一个JsonObjectRequest进请求。

如前所述,构造函数的第一个参数是要使用的HTTP方法。 然后,您可以提供从中获取JSON的URL。 上面的例子中的第三个变量是  null。 这很好,因为它表示没有参数将随请求一起发出。 最后,您有监听器接收JSON响应和错误响应。 如果你想忽略错误,你可以传入null  。

获取图像需要做更多的工作。 有三种请求图像的方法。  ImageRequest 是标准的。 它显示在共同的ImageView中请求的图片,该图片通过提供的URL进行获取。 您可能希望Volley执行的所有解码和调整大小操作都发生在工作线程上。 第二个选项是  ImageLoader 类,您可以将其视为大量的编排者ImageRequests,例如加载ListView 图像。 第三个选项是  NetworkImageView,这是ImageView 布局项的一种XML替代。

我们来看一个例子。

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
mImageView = (ImageView) findViewById(R.id.image);
ImageRequest imgRequest = new ImageRequest(url,
        new Response.Listener<Bitmap>() {
    @Override
    public void onResponse(Bitmap response) {
        mImageView.setImageBitmap(response);
    }
}, 0, 0, ImageView.ScaleType.FIT_XY, Bitmap.Config.ARGB_8888, new Response.ErrorListener() {
    @Override
    public void onErrorResponse(VolleyError error) {
        mImageView.setBackgroundColor(Color.parseColor("#ff0000"));
        error.printStackTrace();
    }
});
Volley.newRequestQueue(this).add(imgRequest);

第一个参数是图片的URL,第二个参数是监听结果的监听器。 第三和第四个参数是整数maxWidth和  maxHeight。 您可以将它们设置0来忽略这些参数。 之后,ImageRequest 请求ScaleType用于计算所需的图像大小和格式来解码位图。 我建议解码格式总是使用Bitmap.Config.ARGB_8888。 最后,我们传递监听错误的监听器。

请注意,Volley会自动将此请求的优先级设置为LOW

1
2
3
4
5
6
// Snippet taken from ImageRequest.java,
// in the Volley source code
@Override
public Priority getPriority() {
    return Priority.LOW;
}

发送POST请求

从GET请求切换到POST请求很简单。 您需要更改Request.Method 请求的构造函数并重写getParams方法,返回包含请求参数的Map<String, String> 。

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
String url = "http://httpbin.org/post";
StringRequest postRequest = new StringRequest(Request.Method.POST, url,
        new Response.Listener<String>() {
            @Override
            public void onResponse(String response) {
                try {
                    JSONObject jsonResponse = new JSONObject(response).getJSONObject("form");
                    String site = jsonResponse.getString("site"),
                            network = jsonResponse.getString("network");
                    System.out.println("Site: "+site+"\nNetwork: "+network);
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
        },
        new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                error.printStackTrace();
            }
        }
) {
    @Override
    protected Map<String, String> getParams()
    {
        Map<String, String>  params = new HashMap<>();
        // the POST parameters:
        params.put("site", "code");
        params.put("network", "tutsplus");
        return params;
    }
};
Volley.newRequestQueue(this).add(postRequest);

取消请求

如果要取消所有请求,请将以下代码段添加到  onStop 方法中:

01
02
03
04
05
06
07
08
09
10
11
@Override
protected void onStop() {
    super.onStop();
    mRequestQueue.cancelAll(new RequestQueue.RequestFilter() {
        @Override
        public boolean apply(Request<?> request) {
            // do I have to cancel this?
            return true; // -> always yes
        }
    });
}

这样,您就不用担心用户在onResponse被调用时activity已经被销毁了的可能性。 因为在这种情况下会抛出NullPointerException异常。 

然而,POST和PUT请求应该继续,即使在用户更改activity之后。 我们可以通过使用标签来实现。 构建GET请求时,向其添加一个标签。

1
2
3
// after declaring your request
request.setTag("GET");
mRequestQueue.add(request);

要取消所有待处理的GET请求,我们只需添加以下代码行:

1
mRequestQueue.cancelAll("GET");

这样,您只能取消GET请求,使其他请求保持不变。 请注意,您现在必须手动处理activity过早销毁的情况。

管理Cookie和请求优先级

Volley不提供设置请求的Cookie的方法,也不提供设置优先级。 这可能在将来研究,因为它是一个严重的遗漏。 但是,暂时还要继承Request类。

对于管理cookies,您可以使用请求的标题来重写getHeaders 方法:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class CustomRequest extends JsonObjectRequest {
    // Since we're extending a Request class
    // we just use its constructor
    public CustomRequest(int method, String url, JSONObject jsonRequest,
                         Response.Listener<JSONObject> listener, Response.ErrorListener errorListener) {
        super(method, url, jsonRequest, listener, errorListener);
    }
    private Map<String, String> headers = new HashMap<>();
    /**
     * Custom class!
     */
    public void setCookies(List<String> cookies) {
        StringBuilder sb = new StringBuilder();
        for (String cookie : cookies) {
            sb.append(cookie).append("; ");
        }
        headers.put("Cookie", sb.toString());
    }
    @Override
    public Map<String, String> getHeaders() throws AuthFailureError {
        return headers;
    }
     
}

实现后,您可以使用setCookies直接提供请求的Cookie列表。

01
02
03
04
05
06
07
08
09
10
11
12
// Firstly, you create the list of the cookies,
// conformed to the HTTP conventions
// i.e. key=value
List<String> cookies = new ArrayList<>();
cookies.add("site=code");
cookies.add("network=tutsplus");
// then you invoke your custom method
customRequest.setCookies(cookies);
// and finally add the request to the queue
Volley.newRequestQueue(this).add(customRequest);

对于优先级,您还需要继承Request类,重写getPriority 方法。 实现如下:

01
02
03
04
05
06
07
08
09
10
11
12
Priority mPriority;
public void setPriority(Priority priority) {
    mPriority = priority;
}
@Override
public Priority getPriority() {
    // If you didn't use the setPriority method,
    // the priority is automatically set to NORMAL
    return mPriority != null ? mPriority : Priority.NORMAL;
}

然后,在主线程上,调用这一行代码来设置请求的优先级:

1
customRequest.setPriority(Priority.HIGH);

您可以选择以下四个可能的优先级状态之一:

1
2
3
4
Priority.LOW // images, thumbnails, ...
Priority.NORMAL // residual
Priority.HIGH // descriptions, lists, ...
Priority.IMMEDIATE // login, logout, ...

结论

在本文中,我们研究了Volley网络库的工作原理。 我们首先看到了为什么使用Volley,何时使用Volley而不是已经包含在Android SDK中的另一个解决方案。 然后,我们深入了解该库的细节,查看其工作流程及其支持的请求类型。 最后,我们通过创建简单的请求并实现自定义的请求来处理cookie和优先级,从而达到我们的目的。

在本系列关于Volley的下一部分中,我们将创建一个利用Volley的简单应用程序。 我将展示如何制作火星天气应用程序,使用好奇流动站在火星上收集的天气数据。

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
Asynchronous HTTP Requests in Android Using Volley
Android 各大网络请求库的比较及实战
简单说说NoHTTP
Android网络编程(六)OkHttp3用法全解析
Volley源码分析(1)
如何使用Google Volley网络库发起带Header的HTTP请求?
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服