Android Volley完全解析1:初识Volley的基本用法
原文鏈接:http://blog.csdn.net/guolin_blog/article/details/17482165,CSDN 郭霖
1. Volley簡介
我們平時在開發Android應用的時候不可避免地都需要用到網絡技術,而多數情況下應用程序都會使用HTTP協議來發送和接收網絡數據。Android系統中主要提供了兩種方式來進行HTTP通信,HttpURLConnection和HttpClient,幾乎在任何項目的代碼中我們都能看到這兩個類的身影,使用率非常高。
不過HttpURLConnection和HttpClient的用法還是稍微有些復雜的,如果不進行適當封裝的話,很容易就會寫出不少重復代碼。于是乎,一些Android網絡通信框架也就應運而生,比如說AsyncHttpClient,它把HTTP所有的通信細節全部封裝在了內部,我們只需要簡單調用幾行代碼就可以完成通信操作了。再比如Universal-Image-Loader,它使得在界面上顯示網絡圖片的操作變得極度簡單,開發者不用關心如何從網絡上獲取圖片,也不用關心開啟線程、回收圖片資源等細節,Universal-Image-Loader已經把一切都做好了。
Android開發團隊也是意識到了有必要將HTTP的通信操作再進行簡單化,于是在2013年Google I/O大會上推出了一個新的網絡通信框架——Volley。Volley可是說是把AsyncHttpClient和Universal-Image-Loader的優點集于了一身,既可以像AsyncHttpClient一樣非常簡單地進行HTTP通信,也可以像Universal-Image-Loader一樣輕松加載網絡上的圖片。除了簡單易用之外,Volley在性能方面也進行了大幅度的調整,它的設計目標就是非常適合去進行數據量不大,但通信頻繁的網絡操作,而對于大數據量的網絡操作,比如說下載文件等,Volley的表現就會非常糟糕。
下圖所示的這些應用都是屬于數據量不大,但網絡通信頻繁的,因此非常適合使用Volley。
2. 下載Volley
介紹了這么多理論的東西,下面我們就準備開始進行實戰了,首先需要將Volley的jar包準備好,如果你的電腦上裝有Git,可以使用如下命令下載Volley的源碼:
git clone https://android.googlesource.com/platform/frameworks/volley下載完成后將它導入到你的Eclipse工程里,然后再導出一個jar包就可以了。如果你的電腦上沒有Git,那么也可以直接使用我導出好的jar包,下載地址是:http://download.csdn.net/detail/sinyu890807/7152015
新建一個Android項目,將volley.jar文件復制到libs目錄下,這樣準備工作就算是做好了
3. StringRequest的用法
前面已經說過,Volley的用法非常簡單,那么我們就從最基本的HTTP通信開始學習吧,即發起一條HTTP請求,然后接收HTTP響應。首先需要獲取到一個RequestQueue對象,可以調用如下方法獲取到:
RequestQueue mQueue = Volley.newRequestQueue(context);注意這里拿到的RequestQueue是一個請求隊列對象,它可以緩存所有的HTTP請求,然后按照一定的算法并發地發出這些請求。RequestQueue內部的設計就是非常合適高并發的,因此我們不必為每一次HTTP請求都創建一個RequestQueue對象,這是非常浪費資源的,基本上在每一個需要和網絡交互的Activity中創建一個RequestQueue對象就足夠了。
接下來為了要發出一條HTTP請求,我們還需要創建一個StringRequest對象,如下所示:
StringRequest stringRequest = new StringRequest("http://www.baidu.com", new Response.Listener<String>() { @Override public void onResponse(String response) { Log.d("TAG", response); } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { Log.e("TAG", error.getMessage(), error); } });可以看到,這里new出了一個StringRequest對象,StringRequest的構造函數需要傳入三個參數,第一個參數就是目標服務器的URL地址,第二個參數是服務器響應成功的回調,第三個參數是服務器響應失敗的回調。其中,目標服務器地址我們填寫的是百度的首頁,然后在響應成功的回調里打印出服務器返回的內容,在響應失敗的回調里打印出失敗的詳細信息。
最后,將這個StringRequest對象添加到RequestQueue里面就可以了,如下所示:
mQueue.add(stringRequest);另外,由于Volley是要訪問網絡的,因此不要忘記在你的AndroidManifest.xml中添加如下權限:
<uses-permission android:name="android.permission.INTERNET" />好了,就是這么簡單,如果你現在運行一下程序,并發出這樣一條HTTP請求,就會看到LogCat中會打印出如下圖所示的數據。
沒錯,百度返回給我們的就是這樣一長串的HTML代碼,雖然我們看起來會有些吃力,但是瀏覽器卻可以輕松地對這段HTML代碼進行解析,然后將百度的首頁展現出來。
這樣的話,一個最基本的HTTP發送與響應的功能就完成了。你會發現根本還沒寫幾行代碼就輕易實現了這個功能,主要就是進行了以下三步操作:
不過大家都知道,HTTP的請求類型通常有兩種,GET和POST,剛才我們使用的明顯是一個GET請求,那么如果想要發出一條POST請求應該怎么做呢?StringRequest中還提供了另外一種四個參數的構造函數,其中第一個參數就是指定請求類型的,我們可以使用如下方式進行指定:
StringRequest stringRequest = new StringRequest(Method.POST, url, listener, errorListener);可是這只是指定了HTTP請求方式是POST,那么我們要提交給服務器的參數又該怎么設置呢?很遺憾,StringRequest中并沒有提供設置POST參數的方法,但是當發出POST請求的時候,Volley會嘗試調用StringRequest的父類——Request中的getParams()方法來獲取POST參數,那么解決方法自然也就有了,我們只需要在StringRequest的匿名類中重寫getParams()方法,在這里設置POST參數就可以了,代碼如下所示:
StringRequest stringRequest = new StringRequest(Method.POST, url, listener, errorListener) { @Override protected Map<String, String> getParams() throws AuthFailureError { Map<String, String> map = new HashMap<String, String>(); map.put("params1", "value1"); map.put("params2", "value2"); return map; } };你可能會說,每次都這樣用起來豈不是很累?連個設置POST參數的方法都沒有。但是不要忘記,Volley是開源的,只要你愿意,你可以自由地在里面添加和修改任何的方法,輕松就能定制出一個屬于你自己的Volley版本。
4. JsonRequest的用法
學完了最基本的StringRequest的用法,我們再來進階學習一下JsonRequest的用法。類似于StringRequest,JsonRequest也是繼承自Request類的,不過由于JsonRequest是一個抽象類,因此我們無法直接創建它的實例,那么只能從它的子類入手了。JsonRequest有兩個直接的子類,JsonObjectRequest和JsonArrayRequest,從名字上你應該能就看出它們的區別了吧?一個是用于請求一段JSON數據的,一個是用于請求一段JSON數組的。
至于它們的用法也基本上沒有什么特殊之處,先new出一個JsonObjectRequest對象,如下所示:
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest("http://m.weather.com.cn/data/101010100.html", null, new Response.Listener<JSONObject>() { @Override public void onResponse(JSONObject response) { Log.d("TAG", response.toString()); } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { Log.e("TAG", error.getMessage(), error); } });可以看到,這里我們填寫的URL地址是http://m.weather.com.cn/data/101010100.html,這是中國天氣網提供的一個查詢天氣信息的接口,響應的數據就是以JSON格式返回的,然后我們在onResponse()方法中將返回的數據打印出來。
最后再將這個JsonObjectRequest對象添加到RequestQueue里就可以了,如下所示:
mQueue.add(jsonObjectRequest);這樣當HTTP通信完成之后,服務器響應的天氣信息就會回調到onResponse()方法中,并打印出來。現在運行一下程序,發出這樣一條HTTP請求,就會看到LogCat中會打印出如下圖所示的數據。
由此可以看出,服務器返回給我們的數據確實是JSON格式的,并且onResponse()方法中攜帶的參數也正是一個JSONObject對象,之后只需要從JSONObject對象取出我們想要得到的那部分數據就可以了。
你應該發現了吧,JsonObjectRequest的用法和StringRequest的用法基本上是完全一樣的,Volley的易用之處也在這里體現出來了,會了一種就可以讓你舉一反三,因此關于JsonArrayRequest的用法相信已經不需要我再去講解了吧。
5. 請求的生命周期
請注意那些比較耗時的操作,例如I/O與解析parsing/decoding都是執行在工作線程。你可以在任何線程中添加一個請求,但是響應結果都是返回到主線程的。
下圖1,演示了一個請求的生命周期:
6. 取消請求
對請求Request對象調用cancel()方法取消一個請求。一旦取消,Volley會確保你的響應Handler不會被執行。這意味著在實際操作中你可以在activity的onStop()方法中取消所有pending在隊列中的請求。你不需要通過檢測getActivity() == null來丟棄你的響應handler,其他類似onSaveInstanceState()等保護性的方法里面也都不需要檢測。
為了利用這種優勢,你應該跟蹤所有已經發送的請求,以便在需要的時候可以取消他們。有一個簡便的方法:你可以為每一個請求對象都綁定一個tag對象。然后你可以使用這個tag來提供取消的范圍。例如,你可以為你的所有請求都綁定到執行的Activity上,然后你可以在onStop()方法執行requestQueue.cancelAll(this) 。同樣的,你可以為ViewPager中的所有請求縮略圖Request對象分別打上對應Tab的tag。并在滑動時取消這些請求,用來確保新生成的tab不會被前面tab的請求任務所卡到。
下面一個使用String來打Tag的例子:
1、 定義你的tag并添加到你的請求任務中。
public static final String TAG = "MyTag"; StringRequest stringRequest; // Assume this exists. RequestQueue mRequestQueue; // Assume this exists.// Set the tag on the request. stringRequest.setTag(TAG);// Add the request to the RequestQueue. mRequestQueue.add(stringRequest);2、 在activity的onStop()方法里面,取消所有的包含這個tag的請求任務。
@Override protected void onStop () {super.onStop();if (mRequestQueue != null) {mRequestQueue.cancelAll(TAG);} }當取消請求時請注意:如果你依賴你的響應handler來標記狀態或者觸發另外一個進程,你需要對此進行考慮。再說一次,response handler是不會被執行的。
多級別取消
RequestQueue queue = Volley.newRequestQueue(MainActivity.this); //3. 發起請求 queue.add(stringRequest); //取消單個請求 stringRequest.cancel();//取消一個請求 //取消所有請求 queue.cancelAll(null);//取消請求隊列里面所有的方法 //取消置頂tag的請求 queue.cancelAll("tag1");//取消tag為tag1的一個請求 //請求添加tag-->tag的目的就是為了反查 stringRequest.setTag("tag1"); //兩個不同的請求可以設置同一個tag stringRequest.setTag("tag1"); // stringRequest1.setTag("tag1");生命周期的聯動
StringRequest req2 = null; StringRequest req3 = null; StringRequest req4 = null; StringRequest req5 = null;req1.setTag(this.getClass().getSimpleName()); req2.setTag(this.getClass().getSimpleName()); req3.setTag(this.getClass().getSimpleName()); req4.setTag(this.getClass().getSimpleName()); req5.setTag(this.getClass().getSimpleName());// 取消對應activity里面所有的請求 RequestQueue queue = VolleyTools.getInstance(MainActivity.this).getQueue(); queue.cancelAll(this.getClass().getSimpleName());// MainActivity7. 建立網絡和緩存
一個 RequestQueue 需要兩部分來支持它的工作:一部分是網絡操作,用來傳輸請求,另外一個是用來處理緩存操作的 Cache。在 Volley 的工具箱中包含了標準的實現方式:DiskBasedCache 提供了每個文件與對應響應數據一一映射的緩存實現。 BasicNetwork 提供了一個基于 AndroidHttpClient 或者 HttpURLConnection 的網絡傳輸。
BasicNetwork 是 Volley 默認的網絡操作實現方式。一個 BasicNetwork 必須使用我們的 app 用于連接網絡的 HTTP Client 進行初始化。這個 Client 通常是AndroidHttpClient 或者 HttpURLConnection:
- 對于 app target API level 低于 API 9(Gingerbread)的使用 AndroidHttpClient。在 Gingerbread 之前,HttpURLConnection 是不可靠的。對于這個的細節,請參考 Android’s HTTP Clients。
- 對于 API Level 9 以及以上的,使用 HttpURLConnection。
我們可以通過檢查系統版本選擇合適的 HTTP Client,從而創建一個能夠運行在所有 Android 版本上的應用。例如:
HttpStack stack; ... // If the device is running a version >= Gingerbread... if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {// ...use HttpURLConnection for stack. } else {// ...use AndroidHttpClient for stack. } Network network = new BasicNetwork(stack);下面的代碼片段演示了如何一步步建立一個 RequestQueue:
RequestQueue mRequestQueue;// Instantiate the cache Cache cache = new DiskBasedCache(getCacheDir(), 1024 * 1024); // 1MB cap// Set up the network to use HttpURLConnection as the HTTP client. Network network = new BasicNetwork(new HurlStack());// Instantiate the RequestQueue with the cache and network. mRequestQueue = new RequestQueue(cache, network);// Start the queue mRequestQueue.start();String url ="http://www.myurl.com";// Formulate the request and handle the response. StringRequest stringRequest = new StringRequest(Request.Method.GET, url,new Response.Listener<String>() {@Overridepublic void onResponse(String response) {// Do something with the response} },new Response.ErrorListener() {@Overridepublic void onErrorResponse(VolleyError error) {// Handle error} });// Add the request to the RequestQueue. mRequestQueue.add(stringRequest); ...如果我們僅僅是想做一個單次的請求并且不想要線程池一直保留,我們可以通過使用在前面一課:發送一個簡單的請求(Sending a Simple Request)文章中提到的 Volley.newRequestQueue() 方法,在任何需要的時刻創建 RequestQueue,然后在我們的響應回調里面執行 stop() 方法來停止操作。但是更通常的做法是創建一個 RequestQueue 并設置為一個單例。下面部分將演示這種做法。
8. 使用單例模式
如果我們的應用需要持續地使用網絡,更加高效的方式應該是建立一個 RequestQueue 的單例,這樣它能夠持續保持在整個 app 的生命周期中。我們可以通過多種方式來實現這個單例。推薦的方式是實現一個單例類,里面封裝了 RequestQueue 對象與其它的 Volley 功能。另外一個方法是繼承 Application 類,并在 Application.OnCreate() 方法里面建立 RequestQueue。但是我們并不推薦這個方法,因為一個 static 的單例能夠以一種更加模塊化的方式提供同樣的功能。
一個關鍵的概念是 RequestQueue 必須使用 Application context 來實例化,而不是 Activity context。這確保了 RequestQueue 在我們 app 的生命周期中一直存活,而不會因為 activity 的重新創建而被重新創建(例如,當用戶旋轉設備時)。
下面是一個單例類,提供了 RequestQueue 與 ImageLoader 功能:
public class MySingleton {private static MySingleton mInstance;private RequestQueue mRequestQueue;private ImageLoader mImageLoader;private static Context mCtx;private MySingleton(Context context) {mCtx = context;mRequestQueue = getRequestQueue();mImageLoader = new ImageLoader(mRequestQueue,new ImageLoader.ImageCache() {private final LruCache<String, Bitmap>cache = new LruCache<String, Bitmap>(20);@Overridepublic Bitmap getBitmap(String url) {return cache.get(url);}@Overridepublic void putBitmap(String url, Bitmap bitmap) {cache.put(url, bitmap);}});}public static synchronized MySingleton getInstance(Context context) {if (mInstance == null) {mInstance = new MySingleton(context);}return mInstance;}public RequestQueue getRequestQueue() {if (mRequestQueue == null) {// getApplicationContext() is key, it keeps you from leaking the// Activity or BroadcastReceiver if someone passes one in.mRequestQueue = Volley.newRequestQueue(mCtx.getApplicationContext());}return mRequestQueue;}public <T> void addToRequestQueue(Request<T> req) {getRequestQueue().add(req);}public ImageLoader getImageLoader() {return mImageLoader;} }下面演示了利用單例類來執行 RequestQueue 的操作:
// Get a RequestQueue RequestQueue queue = MySingleton.getInstance(this.getApplicationContext()).getRequestQueue(); ...// Add a request (in this example, called stringRequest) to your RequestQueue. MySingleton.getInstance(this).addToRequestQueue(stringRequest);好了,關于Volley的基本用法就講到這里,下篇文章中我會帶領大家繼續探究Volley。感興趣的朋友請繼續閱讀Android Volley完全解析(二),使用Volley加載網絡圖片。
總結
以上是生活随笔為你收集整理的Android Volley完全解析1:初识Volley的基本用法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 抓包工具Wireshark基本介绍和学习
- 下一篇: Android Volley完全解析2: