Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android應用開發:網絡工具——Volley(一)

Android應用開發:網絡工具——Volley(一)

編輯:關於Android編程

引言

 

網絡一直是我個人的盲點,前一陣子抽出時間學習了一下Volley網絡工具的使用方法,也透過源碼進行了進一步的學習,有一些心得想分享出來。在Android開發中,成熟的網絡工具不少,Android自帶了HttpClient,還有okhttp,還有koush大神創建的ion開源項目,然後就是google後來加入到Android項目源碼中的Volley。為什麼使用Volley,是因為Volley使用簡單,邏輯清晰,即使在調試過程中出現了問題,也可以快速的通過源碼進行定位。

 

Volley編譯

 

因為已經習慣了使用Gradle構架應用,所以我在第一次想要使用Volley的時候嘗試尋找是否可以通過gradle的配置文件進行庫依賴。可惜的是,並沒有。但即使這樣Volley的庫也很容易做出來加入到我們的工程中。

 

首先需要ant編譯工具,然後如果有Android系統源碼的話,Volley在frameworks/volley目錄下。如果沒有Android源碼,也很好辦,可以單獨從Android的倉儲中克隆出Volley源碼:

 

git clone https://android.googlesource.com/platform/frameworks/volley
不幸的是,volley庫的源碼Android並沒有托管在其在Github的帳號上,所以只能在googlesource上進行克隆,當然在國內也就需要先FQ才可以了。

 

下圖為Volley源碼結構:

\

克隆成功後,可以方便的使用ant進行編譯,當然,如果是在完整的Android源碼下,也可以直接通過make進行編譯,但是時間必然會長很多。這裡使用ant編譯為例,執行:

 

ant jar
結果如圖所示:

 

\

這樣jar包就生成了,很方便吧,接下來將其添加到工程中就可以使用了。
 

Volley使用

 

Volley的網絡請求父類為Request,可以提供給開發者進行繼承,同時也預置了幾種開發中常用的請求類型,下邊介紹兩個:StringRequest和JsonObjectRequest。

為了更加貼近實際使用,下邊將使用Volley與Cloudant進行通訊做示例。Cloudant是一家提供雲服務業務的公司,其向開發者提供免費的雲存儲、雲數據庫服務。關於其注冊等流程本文不做敘述,很簡單的。直接從登錄開始:

 

1. 申請網絡請求隊列

Volley的一個很大的特色,就是所有的網絡請求無需開發者自己執行,而是在請求構造完成後扔到Volley的請求隊列中,隊列依次進行請求,這樣就省去了很多麻煩,開發者也不用擔心網絡請求是否會沖突,是否會在主線程,這些煩心事Volley的網絡隊列都幫我們解決了。

一般來說,一個應用程序如果網絡請求沒有特別頻繁則完全可以只有一個請求隊列(對應Application),如果非常多或其他情況,則可以是一個Activity對應一個網絡請求隊列,具體情況具體分析。下邊的代碼展示了如何申請一個Volley網絡請求隊列:

 

RequestQueue mQueue;
mQueue = Volley.newRequestQueue(getApplicationContext());

這樣就成功申請了一個網絡請求隊列,如果只有一個,則可以在Application中進行申請。

 

2. 使用Volley登錄Cloudant

假設已經成功注冊,登錄名foo,密碼bar。

通過查閱Cloudant的登錄認證文檔:https://docs.cloudant.com/api/authn.html。可以發現Cloudant登錄認證相關接口有三個:

\

這裡我們使用POST方法進行cookie登錄認證。結合上邊假設的用戶名和密碼可知:

 

要訪問的url為 foo.cloudant.com/_session
頭信息為 Content-Type: application/x-www-form-urlencoded
參數為 name = foo, password = bar

 

若訪問成功,我們就可以在網絡回應中獲取cookie,以備之後其他操作使用。顯然,這個請求跟json毫無關系,應該使用StringRequest,StringRequest有兩種構造方法:

public StringRequest(int method, String url, Listener listener, ErrorListener errorListener)

public StringRequest(String url, Listener listener, ErrorListener errorListener)
第二個方法只有GET請求才可以使用,第一個方法的method參數可以用來自定義請求類型,這裡我們需要的是POST,所以應該使用第一個構造方法:

 

 

StringRequest request = new StringRequest(
                Request.Method.POST,
                http://foo.cloudant.com/_session,
                new Response.Listener() {
                    @Override
                    public void onResponse(String s) {  //收到成功應答後會觸發這裡

                    }
                },
                new Response.ErrorListener() {
                    @Override
                    public void onErrorResponse(VolleyError volleyError) { //出現連接錯誤會觸發這裡
                    }
                }
        );

上邊的代碼中,我們成功構造了一個StringRequest,其中已經包含了我們需要的POST和正確的URL,同時還添加了網絡回應監聽器。但是,還缺少文檔要求我們的頭信息和參數。StringRequest在構造中並不提供這些信息的定義,這也是與其他常用網絡工具不同的地方,剛接觸的同學可能會很不適用,通過復寫StringRequest的兩個方法就可以將這些信息放進去了。下邊來完善這個請求:

 

StringRequest request = new StringRequest(
                Request.Method.POST,
                http://foo.cloudant.com/_session,
                new Response.Listener() {
                    @Override
                    public void onResponse(String s) {

                    }
                },
                new Response.ErrorListener() {
                    @Override
                    public void onErrorResponse(VolleyError volleyError) {

                    }
                }
        ) {
            @Override
            public Map getHeaders() throws AuthFailureError {  //設置頭信息
                Map map = new HashMap();
                map.put(Content-Type, application/x-www-form-urldecoded);
                return map;
            }

            @Override
            protected Map getParams() throws AuthFailureError {  //設置參數
                Map map = new HashMap();
                map.put(name, foo);
                map.put(password, bar);
                return map;
            }
        };

相比第一次我們的構造過程,這一次多了兩個復寫的方法來設置頭信息和參數,很容易吧。這個時候請求基本完成了,但是卻缺少另一個很重要的東西,我們的登錄認證為的是拿回屬於自己的cookie,如果不能獲取cookie的話,多麼正確的請求格式都是白費力氣啊,想要拿到cookie一樣也是通過復寫另一個方法進行獲取:

 

            @Override
            protected Response parseNetworkResponse(NetworkResponse response) {
                for (String s : response.headers.keySet()) {
                    if (s.contains(Set-Cookie)) {
                        mCookie = response.headers.get(s);
                        break;
                    }
                }
                return super.parseNetworkResponse(response);
            }
在網絡請求成功後,服務端返回應答信息,而我們所需的Cookie信息就在這些應答信息中,通過對應答信息的遍歷查找,很方便就可以找到我們所需的信息了。到這裡,我們的登錄認證請求就構造完成了,最後需要做的就是將這個StringRequest扔到我們的請求隊列中去:

 

 

mQueue.add(request);
網絡通暢的情況下,很快就能夠獲取Cookie信息了。

 

3. 查看測試文檔

在注冊Cloudant成功後,Cloudant會在我們的帳號中創建一個默認數據庫——crud,其中保存著一行測試數據welcome。

\

讓我們用Volley來訪問這條數據。查閱Cloudant API文檔Documents相關可以發現:

\

通過簡單的GET請求搭配正確的URL即可得到文件(數據)內容,當然,這一切的前提是我們已經掌握了正確的Cookie數據。那麼,我們需要:

 

1. 請求頭數據中包含正確的Cookie信息
2. 訪問正確的URL
3. 請求類型:GET
假設通過上一步登陸認證後我們將Cookie信息保存在了mCookie字符串變量中。而我們需要訪問的URL通過查閱文檔也可以得出路徑為 數據庫名 + 文檔名,即foo.cloudant.com/crud/welcome。萬事俱備,使用StringRequest:

 

 

        StringRequest request = new StringRequest(
                http://foo.cloudant.com/crud/welcome,
                new Response.Listener() {
                    @Override
                    public void onResponse(String s) {

                    }
                },
                new Response.ErrorListener() {
                    @Override
                    public void onErrorResponse(VolleyError volleyError) {

                    }
                }
        ) {
            @Override
            public Map getHeaders() throws AuthFailureError {
                Map map = new HashMap();
                map.put(Cookie, mCookie);
                return map;
            }
        };
        mQueue.add(request);

在onResponse中我們會收到welcome這條數據的json形式字符串:

 

\

簡單的網絡請求StringRequest完全處理得來,使用也比較簡單,就介紹到這裡。下邊介紹JsonObjectRequest應用方法。

 

4. 使用JsonObjectRequest創建新數據


首先看一下JsonObjectRequest的構造方法:
public JsonObjectRequest(int method, String url, JSONObject jsonRequest, Listener listener, ErrorListener errorListener)

public JsonObjectRequest(String url, JSONObject jsonRequest, Listener listener, ErrorListener errorListener)
第一種方法參數以此為:請求方法,訪問的URL,Json數據對象,請求成功監聽器,請求失敗監聽器。 第二種構造方法中,若jsonRequest為空,則方法自動為GET,不為空則自動切換為POST,其他參數含義相同。

Cloudant的文檔(https://docs.cloudant.com/api/documents.html)要求創建文檔可以使用POST或PUT方法進行,所攜帶的數據均為json格式。這樣以來,StringRequest就顯得力不從心了,我們需要使用到Volley的另一個自帶請求類型:JsonObjectRequest。下邊以POST方式創建數據為例,通過查看Cloudant文檔,可知:

 

1. 訪問的URL path為數據庫目錄
2. Content-Type被要求為application/json
3. 攜帶的數據要求為json數據

 

既然方法要求為POST,我們又是創建數據,肯定數據內容不會為空,所以我們選擇第二種構造方法。首先,創建一個Json對象:

 

        JSONObject jsonObject = new JSONObject();
        jsonObject.put(_id, testinfo);
        jsonObject.put(person, foo);
        jsonObject.put(phone, bar);

在Cloudant數據存儲系統中,id可以由開發者指定。接下來進行JsonObjectRequest的構造和請求:

 

 

        JsonObjectRequest request = new JsonObjectRequest(
                http://foo.cloudant.com/crud,
                jsonObject,
                new Response.Listener() {
                    @Override
                    public void onResponse(JSONObject jsonObject) {

                    }
                },
                new Response.ErrorListener() {
                    @Override
                    public void onErrorResponse(VolleyError volleyError) {

                    }
                }
        ) {
            @Override
            public Map getHeaders() throws AuthFailureError {
                Map map = new HashMap();
                map.put(Cookie, mCookie);
                return map;
            }
        };
        mQueue.add(request);

jsonObject數據不為空,所以請求方式自動切換為POST,url為所要創建數據所在的數據庫所在路徑,然後就是請求結果的監聽器,最後別忘了將Cookie帶上,否則會出現認證錯誤的。最後,將構造完成的請求丟進隊列中,由Volley進行調度處理。這個時候不妨再回頭看一看之前分析的請求所需要哪些元素,不難發現,Volley的json請求中,並沒有對Content-Type進行特殊設定。JsonObjectRequest是繼承於JsonRequest的,而JsonRequest已經幫我們完成了這個動作:

 

 

    @Override
    public String getBodyContentType() {
        return PROTOCOL_CONTENT_TYPE;
    }

PS:設置Content-Type也可以通過復寫getBodyContentType這個函數,而不用總是麻煩的使用getHeader中的map進行設定,兩種設定方式效果一致。而且也不用擔心編碼格式,因為默認就是utf-8的:

 

 

    /** Charset for request. */
    private static final String PROTOCOL_CHARSET = utf-8;

    /** Content type for request. */
    private static final String PROTOCOL_CONTENT_TYPE =
        String.format(application/json; charset=%s, PROTOCOL_CHARSET);

到這裡,Json請求的相關用法也就介紹完了。下一節將會從源碼角度分析一下Volley請求的邏輯順序究竟是怎樣的,如果我們需要書寫自己的請求類型,都需要復寫哪些函數,以及需要注意些什麼。

 

 

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved