Android 網絡編程系列(5)Volley 網絡框架入門

前言

上篇文章中咱們對 HttpUrlConnection 的相關用法稍做介紹,能夠看到若是不對它進行封裝,那麼每次使用時就必須寫不少重複的代碼,而且須要本身建立線程進行網絡鏈接,獲取到響應結果後還須要切換回主線程來更新 UI。這樣的過程已經足夠麻煩,若是在獲取網絡圖片或者進行文件下載的場景時,更是須要藉助 AsyncTask 等進行實現,這樣繁雜的步驟顯然是不利於開發的。php

Google 在 2013 年的 IO 大會上針對 Android 中缺乏一個功能強大、體驗良好的網絡加載類這個問題,推出了咱們今天介紹的主角——Volley。Volley 框架能夠說是將AsyncHttpClient、Universal-Image-Loader 等第三方網絡加載框架和圖片加載框架的優勢集於一身。既將網絡加載功能封裝的很是簡單,又可以實現很是複雜的網絡加載任務,好比圖片壓縮和緩存。Volley 的含義翻譯過來是萬箭齊發,它很是適合於處理那些數據量不大但通訊極爲頻繁的網絡請求任務,但在涉及通訊數據量很大的任務中(如文件下載),Volley 的表現就要差不少。下圖是 IO 大會上介紹 Volley 時配圖:html

pic
pic

導入 Volley

Volley 並不在 Android SDK 中,因此若是要使用 Volley 就必須在項目中導入 Volley 這個庫。Volley 沒有官方的Maven repository 或者 Jcenter repository,因此必須依賴於 Volley 的源代碼。android

在項目中導入 Volley 主要有這樣幾種方式:git

1. 下載 volley 的源碼並將其做爲項目的一個 module。github

在 Android Studio 中咱們能夠將第三方的代碼做爲咱們項目工程的一個 module。這個作法是最合適的,不只能夠直接在 IDE 中查看 Volley 的源碼,還能夠在源碼基礎是上進行修改。api

第一步,下載 Volley 源碼,使用 Git 能夠輕鬆實現這一步:緩存

git clone https://github.com/google/volley.git複製代碼

第二步:在 Android Studio 中選擇「File」→「New」→「Import Module」,而後選擇下載好的 Volley 文件夾。這樣就導入了 Volley 的源碼做爲咱們項目中的一個 module。bash

第三步:選擇「File」→「Project Structure」,將 Volley module 做爲咱們 app module 的依賴。服務器

dependent
dependent

通過上述三步,就能夠順利地在咱們本身的代碼中使用 Volley 的功能了。網絡

2. 在依賴列表中添加以下一段依賴:

compile 'com.mcxiaoke.volley:library-aar:1.0.15'複製代碼

這是官方 repository 的一個鏡像,最簡單直接,但不被官方所支持。

3. 將打包好的 jar 文件添加到項目 libs 目錄下。

點擊這裏下載 CSDN 上打包好的 jar 文件。

Volley 基礎用法

1. StringRequest 的使用

在項目中成功導入 Volley 後,下面咱們就來進入正題,學習一下 Volley 的相關用法。Volley 的整體設計思路是基於一個 RequestQueue(請求隊列),開發者只須要建立適合應用場景的 Request,並將其添加到 RequestQueue 便可實現網絡請求。

結合這個設計思路,咱們很快就能夠提取出 Volley 通用的使用步驟:

  1. 建立 RequestQueue 對象。
  2. 建立 Request 對象,一般是 Request 的子類對象。
  3. 將 Request 對象添加到 RequestQueue 中。

首先來看看 StringRequest 的使用。它是 Request 的一個子類,顧名思義這個 Request 會返回一段字符串類型的響應數據。

咱們按照上述的三個步驟來進行說明。

建立 RequestQueue 對象

使用 Volley.newRequestQueue() 方法建立 RequestQueue 對象,傳入當前的上下文(Context)。

RequestQueue mQueue = Volley.newRequestQueue(this);複製代碼

RequestQueue 能夠緩存全部的 Http 請求,而且適合高併發的網絡請求,因此不須要爲每一個 Http 請求都建立一個 RequestQueue 對象,一般在一個 Activity 中建立一個全局的 RequestQueue 對象,甚至若是你的應用程序網絡功能不多時,整個應用中只需有一個 RequestQueue 對象便可(對應 Application)。

建立 StringRequest 對象

接下來須要咱們指定具體請求的內容,因此咱們新建一個 StringRequest 對象,如如下代碼所示:

//獲取控件
TextView tvCode = (TextView) findViewById(R.id.string_code);
//請求的 URL 地址
String url = "http://lixiaoyu.cc";
//建立 StringRequest 對象
StringRequest request = new StringRequest(url, new Response.Listener<String>() {
    @Override
    public void onResponse(String response) {
        tvCode.setText(response);
    }
}, new Response.ErrorListener() {
    @Override
    public void onErrorResponse(VolleyError error) {
        error.printStackTrace();
        tvCode.setText("出錯了");
    }
});複製代碼

StringRequest 共有兩個構造方法,一個有 3 個參數,用於默認以 GET 方式發送網絡請求,這 3 個參數分別是:

String url:請求的網址
Listener< String> listener:響應成功的回調函數
ErrorListener errorListener:響應失敗的回調函數

例如上面代碼中,網址爲個人我的博客網站的 URL,響應成功時直接將該頁面的 HTML 代碼顯示在 TextView 中,響應失敗則在 TextView 顯示一段錯誤提示。(上述兩個回調函數都是直接在主線程中執行,因此不須要咱們本身去切換線程,太方便了)

若是須要使用 POST 方法向網頁提交數據,就須要使用 4 個參數的構造方法。參數分別爲:

int method:網絡請求方式,取值能夠是 Request.Method.POST,Request.Method.HEAD 等
String url
Listener listener
ErrorListener errorListener

後 3 個參數與上面都是一致的。使用 POST 時,咱們須要將數據發送給服務器,Volley 並無設計在構造方法中加入相似 Params 這種參數,可是 Volley 在處理 POST 請求時,會調用 StringRequest 的父類 Request 的 getParams() 方法,咱們能夠在這個方法中加入想要提交到服務器的數據。如如下代碼所示:

//獲取控件
TextView tvCode = (TextView) findViewById(R.id.string_code);
//請求的 URL 地址
String url = "http://ip.taobao.com/service/getIpInfo.php";
StringRequest request = new StringRequest(Request.Method.POST, url,
                new Response.Listener<String>() {
            @Override
            public void onResponse(String response) {
                tvCode.setText(response);
            }
        },
        new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                tvCode.setText("出錯了");
            }
        }){
    @Override
    protected Map<String, String> getParams() throws AuthFailureError {
        Map<String, String> map = new HashMap<>();
        map.put("ip","192.168.0.188");
        return map;
    }
};複製代碼

在代碼中,首先指定構造方法的第一個參數爲 POST,而後其餘參數的設置與以前一致。覆蓋父類中的 getParams() 方法,經過 Map 構造想要提交的數據,最後返回給 Request。

將 StringRequest 對象添加到 RequestQueue 中

最後一步就是將 Request 對象添加到 RequestQueue 中,RequestQueue 就能自動處理這個請求,並將相應結果發送到請求的回調函數中。如如下代碼所示:

mQueue.add(request);複製代碼

2. JsonRequest 的使用

網絡請求的相應結果一般是 XML 格式和 Json 格式,在 Android 開發中不少時候都是 Json 格式。Volley 中定義了 JsonRequest 來方便、快速地實現響應結果爲 Json 的網絡請求。JsonRequest 是一個抽象類,有兩個子類,JsonObjectRequest 和 JsonArrayRequest,返回結果分別是 JsonObject 對象和 JsonArray 對象。

JsonRequest 的使用方式和 StringRequest 有着高度的一致性,咱們以 JsonObjectRequest 爲例(JsonArrayRequest 用法徹底同樣):

/**
 * 1.建立全局的 RequestQueue,爲了顯示方便寫在一塊了
 */
mQueue = Volley.newRequestQueue(this);
/**
 * 2.建立 JsonObjectRequest 對象,設置 URL,這裏使用了 Gank 的 API 接口
 * 和請求一塊兒 POST 到服務器的 JsonObject 對象,這裏設置爲 null,
 * 響應成功或失敗的回調函數
 */
String url = "http://gank.io/api/random/data/Android/2";
JsonObjectRequest request = new JsonObjectRequest(url, null,
                new Response.Listener<JSONObject>() {
    @Override
    public void onResponse(JSONObject response) {
        Log.i("TAG", "onResponse: " + response.toString());
        try {
            boolean isError = response.getBoolean("error");
            if (!isError) {
                JSONArray results = response.getJSONArray("results");
                JSONObject index = results.getJSONObject(0);
                String title = index.getString("desc");
                tvJson.setText(title);
            }
        } catch (JSONException e) {
            e.printStackTrace();
        }
   }
},new Response.ErrorListener() {
    @Override
    public void onErrorResponse(VolleyError error) {
        tvJson.setText("出錯了");
    }
});
/**
 * 3.將 JsonObjectRequest 對象添加到 RequestQueue 中
 */
mQueue.add(request);複製代碼

經過上面的代碼能夠看到,使用步驟是徹底一致的,只是在響應成功時回調函數的泛型從 String 類型變成了 JsonObject 類型,咱們在這個回調函數中就能夠對獲取到的 Json 數據進行處理,提取出想要的信息。

使用 Volley 加載網絡圖片

Volley 的另外一個強大功能就體如今可以很是方便地進行網絡圖片的加載,而且可以對圖片進行壓縮、緩存等處理,不用擔憂圖片過大時所致使的內存泄漏等問題。

使用 Volley 來加載網絡圖片主要有三種方式,一是使用 ImageRequest,二是使用 ImageLoader,三是使用 NetworkImageView 這個自定義控件。下面依次來介紹一下。

使用 ImageRequest

因爲加載網絡圖片也是很是常見的網絡請求之一,因此 Volley 中也封裝了專門用於圖片加載的 ImageRequest,它一樣是 Request 的子類,因此使用方法和上述的 StringRequest、JsonRequest 如出一轍。示例代碼以下:

ImageView imageView = (ImageView) findViewById(R.id.image_img);
RequestQueue queue = Volley.newRequestQueue(this);
String imgUrl = "http://image.wufazhuce.com/FiBzmwDotMhGiJjSuqi1Lg5h_Zjm";
ImageRequest request = new ImageRequest(imgUrl, new Response.Listener<Bitmap>() {
    @Override
    public void onResponse(Bitmap response) {
        imageView.setImageBitmap(response);
    }
}, 0, 0, Bitmap.Config.RGB_565, new Response.ErrorListener() {
    @Override
    public void onErrorResponse(VolleyError error) {
        imageView.setImageResource(R.mipmap.ic_launcher);
    }
});
queue.add(request);複製代碼

若是加載圖片成功就設置給 ImageView,若是加載失敗就在 ImageView 上顯示一張默認的圖片。ImageRequest 使用時須要注意其構造方法,它有兩個構造方法,一個有 6 個參數,一個有 7 個參數,直接看看最全參數列表:

String url:須要加載的圖片地址
Response.Listener< Bitmap> listener:響應成功的回調,好比設置給 ImageView
int maxWidth:圖片的最大寬度
int maxHeight:圖片的最大高度,若是圖片的實際寬高超過設置的最大寬高值,會對圖片進行壓縮,以指定大小進行顯示,最大寬高均設置爲 0 表示不進行任何壓縮。
ScaleType scaleType:圖片的縮放方式,這個參數能夠省略,默認是以總體向中心縮放的方式
Config decodeConfig:圖片 Bitmap 的編碼方式,值爲 Bitmap.Config 類中的常量,有 RGB_565, ARGB_8888等值。
Response.ErrorListener errorListener:響應失敗的回調,好比給 ImageView 設置一張默認顯示的圖片

實際運行效果以下:

imgrequest
imgrequest

使用 ImageLoader

ImageLoader 內部一樣是用 ImageRequest 實現的,而且可以在此基礎上實現圖片的緩存,還能夠過濾掉重複的連接,避免重複發送請求,比 ImageRequest 更加高效。

ImageLoader 的用法就和前面提到的 Request 子類的用法有所不一樣。步驟主要有:

1. 建立一個 RequestQueue 對象。這步與上述一致,不用多說。

RequestQueue mQueue = Volley.newRequestQueue(this);複製代碼

2. 建立一個 ImageLoader 對象。傳入 RequestQueue 對象和 ImageCache 對象做爲參數,這裏先建立一個空的 ImageCache 實例。

ImageLoader loader = new ImageLoader(queue, new ImageLoader.ImageCache() {
    @Override
    public Bitmap getBitmap(String url) {
        return null;
    }

    @Override
    public void putBitmap(String url, Bitmap bitmap) {

    }
});複製代碼

3. 獲取一個 ImageListener 對象。使用 ImageLoader 的 getImageListener() 方法能夠獲取到 ImageListener 對象,在參數中設置須要加載圖片的 ImageView,默認圖片和加載失敗顯示的圖片。

ImageView imageView = (ImageView) findViewById(R.id.image_img);

ImageLoader.ImageListener listener = ImageLoader.getImageListener(imageView,
            R.mipmap.ic_launcher,R.mipmap.ic_launcher_round);複製代碼
  1. 調用 ImageLoader 的 get() 方法加載圖片,傳入網絡圖片地址、ImageListener 對象以及最大寬高。
loader.get(imgUrl, listener,200,200);複製代碼

實際運行效果如圖所示,和 ImageRequest 不一樣, ImageLoader 會先在 ImageView 上顯示設置的默認圖片,等圖片加載成功後進行替換,若加載失敗則顯示設置的失敗圖片。

loader
loader

咱們這裏雖然實現了與 ImageRequest 相同效果的功能,可是並無將 ImageLoader 的優點發揮出來,由於咱們在建立 ImageLoader 時第二個參數是 ImageCache 的一個空實現。咱們應該在這裏對圖片進行緩存處理。

如下這段代碼來自郭神的 Volley 文章,演示了使用 LruCache 來緩存圖片,避免重複加載和內存泄漏。

public class BitmapCache implements ImageCache {  

    private LruCache<String, Bitmap> mCache;  

    public BitmapCache() {  
        int maxSize = 10 * 1024 * 1024;  
        mCache = new LruCache<String, Bitmap>(maxSize) {  
            @Override  
            protected int sizeOf(String key, Bitmap bitmap) {  
                return bitmap.getRowBytes() * bitmap.getHeight();  
            }  
        };  
    }  

    @Override  
    public Bitmap getBitmap(String url) {  
        return mCache.get(url);  
    }  

    @Override  
    public void putBitmap(String url, Bitmap bitmap) {  
        mCache.put(url, bitmap);  
    }  

}
ImageLoader imageLoader = new ImageLoader(mQueue, new BitmapCache());複製代碼

使用 NetworkImageView

NetworkImageView 是 Volley 中的一個自定義控件,繼承自 ImageView,擁有 ImageView 的所有功能,而且實現了加載網絡圖片的功能。它的用法也能夠大體分爲以下幾步:

1. 建立一個 RequestQueue 對象。
2. 建立一個 ImageLoader 對象。

以上兩步就不用多說了,和 ImageLoader 中是同樣的。

RequestQueue mQueue = Volley.newRequestQueue(this);
ImageLoader loader = new ImageLoader(queue, new ImageLoader.ImageCache() {
    @Override
    public Bitmap getBitmap(String url) {
        return null;
    }

    @Override
    public void putBitmap(String url, Bitmap bitmap) {

    }
});複製代碼

3. 在佈局文件中申明 NetworkImageView 控件。

<com.android.volley.toolbox.NetworkImageView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_margin="20dp"
    android:id="@+id/networkiv"/>複製代碼

4. 在 Activity 中對控件進行實例化。同時能夠進行一些自定義的設置。

ImageView imageView = (NetworkImageView) findViewById(R.id.networkiv);

imageView.setDefaultImageResId(R.mipmap.ic_launcher);
        imageView.setErrorImageResId(R.mipmap.ic_launcher_round);複製代碼

這裏咱們一樣設置了默認顯示的圖片和加載失敗時顯示的圖片。

5. 調用NetworkImageView的setImageUrl() 方法加載圖片。將網絡圖片地址和 ImageLoader 對象傳入便可。

String imgUrl = "http://image.wufazhuce.com/FiBzmwDotMhGiJjSuqi1Lg5h_Zjm";
imageView.setImageUrl(imgUrl, loader);複製代碼

這裏有一個須要注意的地方是,在 ImageRequest 和 ImageLoader 中,咱們均可以指定圖片的最大寬高,而在 NetworkImageView 中,並無相應的實現。這是由於 NetworkImageView 是一個控件,在申明控件時就會進行寬高的設置,NetworkImageView 會將加載的圖片寬高和控件寬高進行比較,若是超過就會進行壓縮,若是控件的寬高都指定爲 wrap_content,則不會壓縮。

結語

這篇文章中比較詳細地介紹了 Volley 的來歷和基礎的用法,包括獲取普通的字符串數據和 Json 格式的數據,以及如何使用 Volley 加載網絡圖片。在有關圖片緩存的部分,由於不瞭解 LruCache 的有關內容,因此引用了部分其餘人的代碼,以做示例。

謝謝,下篇文章見。

參考資料

郭霖:初識Volley的基本用法
blog.csdn.net/guolin_blog…
郭霖:使用Volley加載網絡圖片
blog.csdn.net/guolin_blog…
劉望舒:Volley 用法全解析
liuwangshu.cn/application…
泡在網上的日子:Android 網絡通訊框架Volley簡介
www.jcodecraeer.com/a/anzhuokai…
泡在網上的日子:網絡請求庫Volley詳解
www.jcodecraeer.com/a/anzhuokai…

相關文章
相關標籤/搜索