上篇文章中咱們對 HttpUrlConnection 的相關用法稍做介紹,能夠看到若是不對它進行封裝,那麼每次使用時就必須寫不少重複的代碼,而且須要本身建立線程進行網絡鏈接,獲取到響應結果後還須要切換回主線程來更新 UI。這樣的過程已經足夠麻煩,若是在獲取網絡圖片或者進行文件下載的場景時,更是須要藉助 AsyncTask 等進行實現,這樣繁雜的步驟顯然是不利於開發的。php
Google 在 2013 年的 IO 大會上針對 Android 中缺乏一個功能強大、體驗良好的網絡加載類這個問題,推出了咱們今天介紹的主角——Volley。Volley 框架能夠說是將AsyncHttpClient、Universal-Image-Loader 等第三方網絡加載框架和圖片加載框架的優勢集於一身。既將網絡加載功能封裝的很是簡單,又可以實現很是複雜的網絡加載任務,好比圖片壓縮和緩存。Volley 的含義翻譯過來是萬箭齊發,它很是適合於處理那些數據量不大但通訊極爲頻繁的網絡請求任務,但在涉及通訊數據量很大的任務中(如文件下載),Volley 的表現就要差不少。下圖是 IO 大會上介紹 Volley 時配圖:html
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 的依賴。服務器
通過上述三步,就能夠順利地在咱們本身的代碼中使用 Volley 的功能了。網絡
2. 在依賴列表中添加以下一段依賴:
compile 'com.mcxiaoke.volley:library-aar:1.0.15'複製代碼
這是官方 repository 的一個鏡像,最簡單直接,但不被官方所支持。
3. 將打包好的 jar 文件添加到項目 libs 目錄下。
點擊這裏下載 CSDN 上打包好的 jar 文件。
在項目中成功導入 Volley 後,下面咱們就來進入正題,學習一下 Volley 的相關用法。Volley 的整體設計思路是基於一個 RequestQueue(請求隊列),開發者只須要建立適合應用場景的 Request,並將其添加到 RequestQueue 便可實現網絡請求。
結合這個設計思路,咱們很快就能夠提取出 Volley 通用的使用步驟:
首先來看看 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);複製代碼
網絡請求的相應結果一般是 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 來加載網絡圖片主要有三種方式,一是使用 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 設置一張默認顯示的圖片
實際運行效果以下:
使用 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);複製代碼
loader.get(imgUrl, listener,200,200);複製代碼
實際運行效果如圖所示,和 ImageRequest 不一樣, ImageLoader 會先在 ImageView 上顯示設置的默認圖片,等圖片加載成功後進行替換,若加載失敗則顯示設置的失敗圖片。
咱們這裏雖然實現了與 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…