关于应用Volley框架 + Android 网络通信框架Volley简介(Google IO 2013)

来源:互联网 发布:房产网免费源码 编辑:程序博客网 时间:2024/05/14 11:56
在android中基于http请求的框架很多,自己如果比较了解http请求流程,自己也可以写一个不错的框架,由于一些原因,项目中我们自己开发的框架被要求用volley替换掉了,因此我不得不对volley这个开发包进行自己的研究,以希望能够熟悉整个流程,以及能够顺利的将这个开源包融入到项目中同时不会影响原有逻辑。(个人风格的原因吧,我不是很喜欢贴大段大段的代码在帖子里面,大家如果能对照volley源码来看这个帖子的话,会更有收获的)
       首先啰嗦些自己对android的http请求框架的一些感悟,如果有不对的地方大家尽情拍砖拍死我吧(就算死了我也要发帖子)。
       我理解的基于网络的应用最核心的其实就是request跟response的分发。这个分发机制写好了,框架够健壮,扩展性高,那么以后涉及到这个层次的改动就少(因为从一开始我们的设计都是比较初级的,会随着需求的不断增多而出现一些需要对框架机制的改动需求),因为对于分发机制的改动是很核心的,说牵一发而动全身一点也不为过,稍微改一点点都会对项目有很大的影响甚至是未知的影响,而且构建得不好的话,有些需求的改动会非常麻烦,而这些改动如果是良好的构架的话往往是可以避免的,所以,在初期能够构建好一些是很有必要的。我大概看过一些开源的项目以及这些年来自己做过的项目(没做过游戏,所以游戏的我不知道哈),感觉基于网络的应用要么用http要么用套接字,如果不需要推送的,一般都是使用http来做。
       http的请求步骤大概分为这么几步,就我看来:
       1)发起request,这里的发起者要是个context之类的(一般是activity或者service)东东,当然很多时候发起者也是最后数据的接受者。不同的框架对于这个发起的机制实现各不相同,但总的说来都是统一给出一个公共接口,让发起者封装好必要的信息,使用公共接口,让其实现类去启动实际的http请求操作,大概主要区别在于如何封装这些request信息。
       2)进行request请求,并获取response。真正的请求和响应就在这里完成,这里可能有两个需要考虑到的,一个是线程的阻塞,有的框架会让线程阻塞直到获取到响应为止,有的框架则会在这里分发出多个线程,以避免这种阻塞,当然大多数都会采用后者了。二个就是数据的存储,有些固定的请求,比如一些不会轻易变动的信息,在第一次请求到了之后就不需要再多次请求了,一般也可以在这个部分完成这个功能。但总而言之,不管你线程分配也好,使用本地数据也好,还是你的请求出问题了也好,总之你必须在一定的时间内,给我的request一个response。
      3)分派response,我们去餐馆吃饭都知道,哪桌点的菜就端到哪桌去,不能端错了。谁发出的request,最后就要给到他的接受者手里,不能给错了。有些框架是靠一些接口类的注入来保证数据的正确接受,有些框架是靠一个寻找机制来保障的(比如广播)。

       好了,说了这么多我们来看看volley吧。前面那么多铺垫也不是白用的,我就按照我理解的这三步来拆析volley框架。
      1)发起request:volley使用Request抽象类来封装请求。Request类也是整个volley项目中最核心的类(还真没有之一)。从源码我们可以看到,Request的实现类有好几种,而这些实现类有个共同的特点就是他们其实已经定义好了response返回的数据类型,也就是说,其实这里的Requst类并不单单只做request,他们也负责对response的数据处理(当然直接使用实现类的话,我们一般不管这些数据如何被处理的),我们可以自己写实现类并实现其中的数据处理方法
         abstract protected Response<T> parseNetworkResponse(NetworkResponse response);
         来将返回数据变成我们想要的类型,然后由我们再来进一步加工处理。
         Request可不单单只做了这么一件事情。为了证明他为什么是最核心的类,我再列举几个他做了的貌似跟他不相关的事情。
         abstract protected void deliverResponse(T response);
         public void deliverError(VolleyError error)

         有木有震惊的赶脚,是的,最后response以及error的分发的实际执行者也是Request。所以这个Request类是贯穿一个请求到响应过程自始至终的类。这个其实不难理解,最后一步的分派工作需要一定的信息来保证分派的正确性,而最能提供这些信息的,其实就是最初我们发出的request了。
         简单的介绍下Request如何使用:
         从源码可以看出 getUrl 是返回的 url地址,getBody是返回的请求参数,这两个方法是在http的实际请求中肯定要用到的,使用get请求的话是需要保证getUrl的返回值正确即可,而使用post的话还要保证后面一个方法的返回值正确。(返回值如何注入就是你们的事情了,构造函数注入也可,set 方法注入也可)这里需要给大家注意的地方原生态的Stringrequest 没有重写getBody 方法,也就是说 getBody 返回为null,那么 volley将默认使用get请求,如果大家想用post请求并使用Stringrequest的话,请重写这个方法。
          另外还有两个很重要的类,请大家在构造request的时候务必要注入,ErrorListener 和 Listener,一个是用来处理error(public void onErrorResponse(VolleyError error))的,一个是用来处理正常返回的(public void onResponse(T response))这两个接口的定义都在Response类中。不难想出上面我所说的两个方法abstract protected void deliverResponse(T response)public void deliverError(VolleyError error)的实现其实就是调用这两个接口各自的方法就可以了。
          有些附加的条件我们可以酌情的考虑是否需要实现。
          public String getCacheKey(),CacheKey是volley从Request获取的用于本地存储请求数据的键值,相信大家很快能明白,如果两个request的这个方法返回的值一样的话,后者将能够有机会取到前者存储在本地的数据,从而减少了网络请求。原生态的Request是使用url为cechekey,这样并不一定科学,有本地存储需求的童鞋,请切记重写此方法。当然前提是保证public final boolean shouldCache()返回为true。否则前功尽弃。
           public void setRetryPolicy(RetryPolicy retryPolicy),从字面意思就可以看出,这个是对一个request的重新请求策略的设置,不同的项目是否需要重新请求,重新请求几次,请求超时的时间,这些就在这设置到里面。一般放就是继承RetryPolicy类,根据自己的需求实现父类方法。

          不知不觉写了这么多,先写到这里吧,后面我再介绍volley如何实现第二步跟第三步。

转载自 : http://www.eoeandroid.com/thread-307046-1-1.html

1. 什么是Volley

在这之前,我们在程序中需要和网络通信的时候,大体使用的东西莫过于AsyncTaskLoader,HttpURLConnection,AsyncTask,HTTPClient(Apache)等,今年的Google I/O 2013上,Volley发布了。Volley是Android平台上的网络通信库,能使网络通信更快,更简单,更健壮。
这是Volley名称的由来: a burst or emission of many things or a large amount at once
在Google IO的演讲上,其配图是一幅发射火弓箭的图,有点类似流星。见下图

其实,从这幅图,我们也可以看出来,Volley特别适合数据量不大但是通信频繁的场景。

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

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

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

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

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

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

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

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

2. 使用前的准备

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

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. git clone https://android.googlesource.com/platform/frameworks/volley  

然后编译为jar包,再在自己的工程里import进来。

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

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

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

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  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();  

3.2. 给ImageView设置图片源

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  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的方法都需要从主线程里来调用。

3.3. 使用NetworkImageView

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

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. mImageView.setImageUrl(url, imageLoader)  

来设定。而且,这个控件在被从父控件detach的时候,会自动取消网络请求的,即完全不用我们担心相关网络请求的生命周期问题。
示例代码如下:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  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。

另外,注意这里:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. mImageLoader = new ImageLoader(mRequestQueue, new BitmapLruCache());  

ImageLoader构造函数的第二个参数是一个ImageCache的实例(严格来说,是实现ImageCache接口的某具体类的实例)
ImageCache的定义如下(在ImageLoader.java里):

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  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

3.5. 使用自己定制的request

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

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. @Override  
  2. protected Response parseNetworkResponse(NetworkResponse response) {  
  3.     try {  
  4.         String json = new String(  
  5.                 response.data, HttpHeaderParser.parseCharset(response.headers));  
  6.         return Response.success(  
  7.                 gson.fromJson(json, clazz), HttpHeaderParser.parseCacheHeaders(response));  
  8.     } catch (UnsupportedEncodingException e) {  
  9.         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的例子:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  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. }  

4. Volley的架构设计

Volley使用了线程池来作为基础结构,主要分为主线程,cache线程和network线程。
主线程和cache线程都只有一个,而NetworkDispatcher线程可以有多个,这样能解决比并行问题。如下图:


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

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. @Override public void onPostExecute(Result r) {  
  2.     if (getActivity() == null) {  
  3.         return;  
  4.     }  
  5.     // ...  
  6. }  

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

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

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


[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. @Override  
  2. public void onStop() {  
  3.     for (Request <?> req : mInFlightRequests) {  
  4.         req.cancel();  
  5.     }  
  6.     ...  
  7. }  

或者,取消这个队列里的所有请求:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. @Override pubic void onStop() {  
  2.     mRequestQueue.cancelAll(this);  
  3.     ...  
  4. }  

也可以根据RequestFilter或者Tag来终止某些请求:

[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. @Override public void onStop() {  
  2.     mRequestQueue.cancelAll( new RequestFilter() {})  
  3.     ...  
  4.     // or  
  5.     mRequestQueue.cancelAll(new Object());  
  6.     ...  

5.总结

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

  • JSON对象
  • 图片加载

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

附录、参考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. Android Tipshttp://dev.classmethod.jp/smartphone/android/android-tips-51-volley/
4. 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


Google IO2013网络框架Volley 演讲PDF下载: http://download.csdn.net/detail/t12x3456/5686041



0 0
原创粉丝点击