天天看點

android 網絡通信架構volly

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的演講上,其配圖是一幅發射火弓箭的圖,有點類似流星。見下圖

android 網絡通信架構volly

其實,從這幅圖,我們也可以看出來,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庫先克隆一個下來:

android 網絡通信架構volly

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

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

注意,這個庫要求最低sdk版本為froyo,即至少要設定android:minsdkversion為8以上。

3.使用例子

下面簡單看看如何使用volley

3.1. 最簡單的get請求

這個例子很簡單,從網絡取得json對象,然後列印出來。

android 網絡通信架構volly

mqueue = volley.newrequestqueue(getapplicationcontext());  

mqueue.add(new jsonobjectrequest(method.get, url, null,  

            new listener() {  

                @override  

                public void onresponse(jsonobject response) {  

                    log.d(tag, "response : " + response.tostring());  

                }  

            }, null));  

mqueue.start();  

3.2. 給imageview設定圖檔源

android 網絡通信架構volly

// imageview是一個imageview執行個體  

// imageloader.getimagelistener的第二個參數是預設的圖檔resource id  

// 第三個參數是請求失敗時候的資源id,可以指定為0  

imagelistener listener = imageloader.getimagelistener(imageview, android.r.drawable.ic_menu_rotate, android.r.drawable.ic_delete);  

mimageloader.get(url, listener);  

imageloader的方法都需要從主線程裡來調用。

3.3. 使用networkimageview

volley提供了一個新的控件networkimageview來代替傳統的imageview,這個控件的圖檔屬性可以通過

android 網絡通信架構volly

mimageview.setimageurl(url, imageloader)  

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

示例代碼如下:

android 網絡通信架構volly

mimageloader = new imageloader(mrequestqueue, new bitmaplrucache());  

... ...  

if(holder.imagerequest != null) {  

    holder.imagerequest.cancel();  

}  

holder.imagerequest = mimageloader.get(base_ur + item.image_url, holder.imageview, r.drawable.loading, r.drawable.error);  

注意,這裡使用的不是imageview控件,而是volley新提供的com.android.volley.networkimageview。

另外,注意這裡:

android 網絡通信架構volly

imageloader構造函數的第二個參數是一個imagecache的執行個體(嚴格來說,是實作imagecache接口的某具體類的執行個體)

imagecache的定義如下(在imageloader.java裡):

android 網絡通信架構volly

/** 

 * simple cache adapter interface. if provided to the imageloader, it 

 * will be used as an l1 cache before dispatch to volley. implementations 

 * must not block. implementation with an lrucache is recommended. 

 */  

public interface imagecache {  

    public bitmap getbitmap(string url);  

    public void putbitmap(string url, bitmap bitmap);  

下面的網址一個lru的cache實作例子,請參考:

<a target="_blank" href="https://github.com/suwa-yuki/volleysample/blob/master/src/jp/classmethod/android/sample/volley/bitmapcache.java">https://github.com/suwa-yuki/volleysample/blob/master/src/jp/classmethod/android/sample/volley/bitmapcache.java</a>

3.5. 使用自己定制的request

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

android 網絡通信架構volly

@override  

protected response parsenetworkresponse(networkresponse response) {  

    try {  

        string json = new string(  

                response.data, httpheaderparser.parsecharset(response.headers));  

        return response.success(  

                gson.fromjson(json, clazz), httpheaderparser.parsecacheheaders(response));  

    } catch (unsupportedencodingexception e) {  

        return response.error(new parseerror(e));  

    } catch (jsonsyntaxexception e) {  

    }  

裡面使用的gson(com.google.gson.gson)是json的序列化和反序列化的庫,可以在json和java model object之間進行轉換。

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

android 網絡通信架構volly

mrequestqueue.add( new gsonrequest(url, listresponse.class, null,  

    new listener() {  

        public void onresponse(listresponse response) {  

            appenditemstolist(response.item);  

            notifydatasetchanged();  

        }  

4. volley的架構設計

volley使用了線程池來作為基礎結構,主要分為主線程,cache線程和network線程。

主線程和cache線程都隻有一個,而networkdispatcher線程可以有多個,這樣能解決比并行問題。如下圖:

android 網絡通信架構volly

如果在一個activity裡面啟動了網絡請求,而在這個網絡請求還沒傳回結果的時候,如果activity被結束了,則我們需要寫如下代碼作為防守:

android 網絡通信架構volly

@override public void onpostexecute(result r) {  

    if (getactivity() == null) {  

        return;  

    // ...  

activity被終止之後,如果繼續使用其中的context等,除了無辜的浪費cpu,電池,網絡等資源,有可能還會導緻程式crash,是以,我們需要處理這種一場情況。

使用volley的話,我們可以在activity停止的時候,同時取消所有或部分未完成的網絡請求。

volley裡所有的請求結果會傳回給主程序,如果在主程序裡取消了某些請求,則這些請求将不會被傳回給主線程。

比如,可以針對某些個request做取消操作:

android 網絡通信架構volly

public void onstop() {  

    for (request &lt;?&gt; req : minflightrequests) {  

        req.cancel();  

    ...  

或者,取消這個隊列裡的所有請求:

android 網絡通信架構volly

@override pubic void onstop() {  

    mrequestqueue.cancelall(this);  

也可以根據requestfilter或者tag來終止某些請求:

android 網絡通信架構volly

@override public void onstop() {  

    mrequestqueue.cancelall( new requestfilter() {})  

    // or  

    mrequestqueue.cancelall(new object());  

5.總結

從演講的例子來看,volley應該是簡化了網絡通信的一些開發,特别是針對如下兩種情況:

json對象

圖檔加載

但是這個東西也有不實用的地方,比如大資料(large payloads ),流媒體,這些case,還需要使用原始的方法,比如download manager等。

總之,如果你要編寫網絡程式,是不是可以考慮開始使用volley呢?