關於應用Volley框架 + Android 網絡通信框架Volley簡介(Google IO 2013)

在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庫先克隆一個下來:

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

然後編譯爲jar包,再在自己的工程裏import進來。

注意,這個庫要求最低SDK版本爲Froyo,即至少要設置android:minSdkVersion爲8以上。

3.使用例子
下面簡單看看如何使用Volley

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();  

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的方法都需要從主線程裏來調用。

3.3. 使用NetworkImageView

Volley提供了一個新的控件NetworkImageView來代替傳統的ImageView,這個控件的圖片屬性可以通過

  1. mImageView.setImageUrl(url, imageLoader)  

來設定。而且,這個控件在被從父控件detach的時候,會自動取消網絡請求的,即完全不用我們擔心相關網絡請求的生命週期問題。
示例代碼如下:

  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

3.5. 使用自己定製的request

我們也可以通過繼承Request根據自己的需求來定製自己的request

  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的例子:

  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被結束了,則我們需要寫如下代碼作爲防守:

  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.     ...  

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



發佈了54 篇原創文章 · 獲贊 3 · 訪問量 44萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章