Android简略、快速的网络库: Volley ( Google IO 2013 )

Android简单、快速的网络库: Volley ( Google IO 2013 )

1、什么是volley

         Volley是Ficus Kirpatrick在Gooogle I/O 2013发布的一个处理和缓存网络请求的库,能使网络通信更快,更简单,更健壮。Volley名称的由来: a burst or emission of many things or a large amount at once。在Google IO的演讲上,其配图是一幅发射火弓箭的图,有点类似流星。见下图

Android简略、快速的网络库: Volley  ( Google IO 2013 )

2、volley能做什么

volley适合小而快的数据传输。Volley应该是简化了网络通信的一些开发,特别是针对以下两种情况:

  • JSON对象
  • 图片加载

Volley的便利功能:

Advantages of using Volley:

  1. Volley automatically schedule all network requests. It means that Volley will be taking care of all the network requests your app executes for fetching response or image from web.
  2. Volley provides transparent disk and memory caching.
  3. Volley provides powerful cancellation request API. It means that you can cancel a single request or you can set blocks or scopes of requests to cancel.
  4. Volley provides powerful customization abilities.
  5. Volley provides Debugging and tracing tools

3、volley架构

    Volley使用了线程池来作为基础结构,主要分为主线程,cache线程和network线程。主线程和cache线程都只有一个,而NetworkDispatcher线程可以有多个,这样能解决比并行问题。具体可以参考下图,此图节选自Google I/O 演讲。


Android简略、快速的网络库: Volley  ( Google IO 2013 )


4、 Volley引入的背景
在以前,我们可能面临如下很多麻烦的问题。

比如以前从网上下载图片的步骤可能是这样的流程:

  • 在ListAdapter#getView()里开始图像的读取。
  • 通过AsyncTask等机制使用HttpURLConnection从服务器去的图片资源
  • 在AsyncTask#onPostExecute()里设置相应ImageView的属性。

而在Volley下,只需要一个函数即可,详细见后面的例子。

再比如,屏幕旋转的时候,有时候会导致再次从网络取得数据。为了避免这种不必要的网络访问,我们可能需要自己写很多针对各种情况的处理,比如cache什么的。

再有,比如ListView的时候,我们滚动过快,可能导致有些网络请求返回的时候,早已经滚过了当时的位置,根本没必要显示在list里了,虽然我们可以通过ViewHolder来保持url等来实现防止两次取得,但是那些已经没有必须要的数据,还是会浪费系统的各种资源。

4.1 Volley提供的功能
简单来说,它提供了如下的便利功能:

  • JSON,图像等的异步下载;
  • 网络请求的排序(scheduling)
  • 网络请求的优先级处理
  • 缓存
  • 多级别取消请求
  • 和Activity和生命周期的联动(Activity结束时同时取消所有网络请求)

4.2. 使用前的准备

引入Volley非常简单,首先,从git库先克隆一个下来:

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

然后编译为jar包,进入到volley工程目录,输入命令如下:

android update project -p .
更新volley项目,然后使用ant编译成jar(相关脚本为build.xml和custom_rules.xml),命令如下:

ant jar
大约几秒后volley.jar会生成在..\volley\bin目录下,最后再在自己的工程里import进来即可使用。

注意,这个库要求最低SDK版本为Froyo,即至少要设置android:minSdkVersion为8以上。


4.3.使用例子
下面简单看看如何使用Volley

4.3.1. 最简单的get请求
这个例子很简单,从网络取得JSON对象,然后打印出来。

1 mQueue = Volley.newRequestQueue(getApplicationContext());
2 mQueue.add(new JsonObjectRequest(Method.GET, url, null,
3             new Listener() {
4                 @Override
5                 public void onResponse(JSONObject response) {
6                     Log.d(TAG, "response : " + response.toString());
7                 }
8             }, null));
9 mQueue.start();
4.3.2. 给ImageView设置图片源
1 // imageView是一个ImageView实例
2 // ImageLoader.getImageListener的第二个参数是默认的图片resource id
3 // 第三个参数是请求失败时候的资源id,可以指定为0
4 ImageListener listener = ImageLoader.getImageListener(imageView, android.R.drawable.ic_menu_rotate, android.R.drawable.ic_delete);
5 mImageLoader.get(url, listener);

ImageLoader的方法都需要从主线程里来调用。

4.3.3. 使用NetworkImageView

Volley提供了一个新的控件NetworkImageView来代替传统的ImageView,这个控件的图片属性可以通过

1 mImageView.setImageUrl(url, imageLoader)
来设定。而且,这个控件在被从父控件detach的时候,会自动取消网络请求的,即完全不用我们担心相关网络请求的生命周期问题。 
示例代码如下:
1 NetworkImageView view = (NetworkImageView) findViewById(R.id.network_image_view);
2 view.setImageUrl(url, new ImageLoader(mQueue, new BitmapCache()));
4.3.4. 使用ImageLoader
1 mImageLoader = new ImageLoader(mRequestQueue, new BitmapLruCache());
2 ... ...
3   
4 if(holder.imageRequest != null) {
5     holder.imageRequest.cancel();
6 }
7 holder.imageRequest = mImageLoader.get(BASE_UR + item.image_url, holder.imageView, R.drawable.loading, R.drawable.error);

注意,这里使用的不是ImageView控件,而是Volley新提供的com.android.volley.NetworkImageView。

另外,注意这里:

1 mImageLoader = new ImageLoader(mRequestQueue, new BitmapLruCache());
ImageLoader构造函数的第二个参数是一个ImageCache的实例(严格来说,是实现ImageCache接口的某具体类的实例) 
ImageCache的定义如下(在ImageLoader.java里):
1 /**
2  * Simple cache adapter interface. If provided to the ImageLoader, it
3  * will be used as an L1 cache before dispatch to Volley. Implementations
4  * must not block. Implementation with an LruCache is recommended.
5  */
6 public interface ImageCache {
7     public Bitmap getBitmap(String url);
8     public void putBitmap(String url, Bitmap bitmap);
9 }

下面的网址一个lru的cache实现例子,请参考:

https://github.com/suwa-yuki/VolleySample/blob/master/src/jp/classmethod/android/sample/volley/BitmapCache.java

4.3.5. 使用自己定制的request

我们也可以通过继承Request根据自己的需求来定制自己的request

01 @Override
02 protected Response parseNetworkResponse(NetworkResponse response) {
03     try {
04         String json = new String(
05                 response.data, HttpHeaderParser.parseCharset(response.headers));
06         return Response.success(
07                 gson.fromJson(json, clazz), HttpHeaderParser.parseCacheHeaders(response));
08     catch (UnsupportedEncodingException e) {
09         return Response.error(new ParseError(e));
10     catch (JsonSyntaxException e) {
11         return Response.error(new ParseError(e));
12     }
13 }

这段代码节选自: https://gist.github.com/ficusk/5474673

里面使用的gson(com.google.gson.Gson)是JSON的序列化和反序列化的库,可以在JSON和java model object之间进行转换。

以下是使用自定制request的例子:

1 mRequestQueue.add( new GsonRequest(url, ListResponse.classnull,
2     new Listener() {
3         public void onResponse(ListResponse response) {
4             appendItemsToList(response.item);
5             notifyDataSetChanged();
6         }
7     }
8 }


5. Volley的架构设计

Volley使用了线程池来作为基础结构,主要分为主线程,cache线程和network线程。
主线程和cache线程都只有一个,而NetworkDispatcher线程可以有多个,这样能解决比并行问题。
具体可以参考下图,此图节选自Google I/O 演讲
Android简略、快速的网络库: Volley  ( Google IO 2013 )

Main Thread

如果在一个Activity里面启动了网络请求,而在这个网络请求还没返回结果的时候,如果Activity被结束了,则我们需要写如下代码作为防守:

1 @Override public void onPostExecute(Result r) {
2     if (getActivity() == null) {
3         return;
4     }
5     // ...
6 }

Activity被终止之后,如果继续使用其中的Context等,除了无辜的浪费CPU,电池,网络等资源,有可能还会导致程序crash,所以,我们需要处理这种一场情况。

使用Volley的话,我们可以在Activity停止的时候,同时取消所有或部分未完成的网络请求。

Volley里所有的请求结果会返回给主进程,如果在主进程里取消了某些请求,则这些请求将不会被返回给主线程。
比如,可以针对某些个request做取消操作:

1 @Override
2 public void onStop() {
3     for (Request <?> req : mInFlightRequests) {
4         req.cancel();
5     }
6     ...
7 }
或者,取消这个队列里的所有请求:
1 @Override pubic void onStop() {
2     mRequestQueue.cancelAll(this);
3     ...
4 }
也可以根据RequestFilter或者Tag来终止某些请求:
1 @Override public void onStop() {
2     mRequestQueue.cancelAll( new RequestFilter() {})
3     ...
4     // or
5     mRequestQueue.cancelAll(new Object());
6     ...

6.总结

从演讲的例子来看,Volley应该是简化了网络通信的一些开发,特别是针对如下两种情况:

  • JSON对象
  • 图片加载

但是这个东西也有不实用的地方,比如大数据(large payloads ),流媒体,这些case,还需要使用原始的方法,比如Download Manager等。
总之,如果你要编写网络程序,是不是可以考虑开始使用Volley呢?
更多内容,可以从源代码获取,见下面附录的连接1.

附录、参考link:
1. Volley主页 https://android.googlesource.com/platform/frameworks/volley
2. Google I/O Volley演讲 http://www.youtube.com/watch?v=yhv8l9F44qo&feature=player_embedded
3. Google I/O 2013 – Android : Volley: Easy, Fast Networking for Android http://y-anz-m.blogspot.jp/2013/05/google-io-2013-android-volley-easy-fast.html?m=1


参考:

 Android网络通信库Volley简介

Google I/O 2013 – Volley: Easy, Fast Networking for Android(ppt)