Volley解析(一)--Volley的使用
Volley解析(一)--Volley的使用
Volley 是一個HTTP協議的網絡請求框架
Volley的優勢:
自動安排網絡請求
支持多個并發網絡連接
具有標準HTTP緩存一致性的透明磁盤和內存響應緩存
支持請求優先級
支持取消請求api。可以取消單個請求,也可以設置要取消的請求的塊或范圍。
定制方便,支持失敗重試和回退
強排序,可以輕松地從網絡異步獲取的數據中正確填充UI。
具有調試和跟蹤工具
它易于與任何協議集成,支持原始字符串、圖像和JSON的解析。通過提供你需要的功能的內置支持,Volley使你從寫樣板代碼脫身,可以讓你專注于特定于應用程序的邏輯。
Volley的優勢劣勢都在于使用內存緩存!!
Volley擅長的場景:
Volley擅長用于填充UI的RPC類型操作,如將搜索結果頁作為結構化數據抓取。適合短小,頻繁的請求。因為解析過程結果會保留在內存。
Volley不擅長的場景:
Volley不適合大型下載或流媒體操作,因為在解析過程中保留了內存中的所有響應。
使用newRequestQueue簡單發送請求
三步完成發送請求:
初始化請求隊列
構造請求對象
請求對象加入請求隊列
Volley提供了一個方便的方法volley.newrequestqueue為用戶配置一個請求隊列.設置使用默認值,并啟動隊列。
final TextView mTextView = (TextView) findViewById(R.id.text);
...
// Instantiate the RequestQueue. 初始化請求隊列
RequestQueue queue = Volley.newRequestQueue(this);
String url ="http://www.google.com";
// Request a string response from the provided URL.構造請求對象
StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
new Response.Listener<String>() {
@Override
public void onResponse(String response) {
// Display the first 500 characters of the response string.
mTextView.setText("Response is: "+ response.substring(0,500));
//UI線程
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
mTextView.setText("That didn't work!");
//UI線程
}
});
// Add the request to the RequestQueue.
queue.add(stringRequest);
Volley總是在主線上傳遞解析的響應。在主線程中運行可以方便與接收的數據填充的UI控件,你可以直接從響應隨意修改UI控件。但是它對庫提供的許多重要語義尤其重要,特別是與取消請求相關的。
一旦添加請求,它就通過管道移動,得到服務,并對其原始響應進行解析。
當調用add,Volley就會跑一個cache線程和一個網絡分發線程池(默認是4個線程的線程池)。
當你添加一個請求隊列,它會進緩存的線程:
如果請求可以從高速緩存中得到服務,緩存響應將在高速緩存線程上解析,解析后的響應將在主線程上傳遞。
如果請求不能從緩存中進行服務,那么它就被放置在網絡隊列中。第一個可用的網絡線程接收來自隊列的請求,執行HTTP事務,解析工作線程上的響應,將響應寫入高速緩存,并將解析后的響應返回到主線程進行傳輸。
注意,諸如阻塞I/O和解析/解碼等昂貴的操作是在工作線程上完成的。可以從任何線程添加請求,但響應總是在主線程上傳遞。
取消一個請求
這種場景是比較常見的。比如在界面銷毀之前,請求就需要取消。
1 最簡單的一個方式就是在請求的對象上直接調cancel()方法:
stringRequest.cancel();
一旦取消,Volley保證的響應Response處理程序將永遠不會被調用。這意味著你可以取消你所有的請求在onstop()方法。而且在響應處理方法里不用檢查getActivity() == null,也不用關心onSaveInstanceState()有沒有被調用,或者去有意其他的一些防御性代碼。
這樣帶來的好處是巨大的,意味著Rrsponse中的任何操作在cancel以后不會執行,那就不會有意外發生。
要利用這種行為,通常需要跟蹤所有正在執行的請求,以便在適當的時候取消它們。
有一個更簡單的方法:可以將標記對象與每個請求關聯起來。然后可以使用此標記來提供取消請求的范圍。
可以將所有請求標記為正在進行的界面。然后再onStop中調requestQueue.cancelAll(this)。同樣,你也可以用tag標記把所有的縮略圖圖片請求和ViewPager中各個相關的tab頁關聯起來。在切換的時候就取消前一個tab的請求們
2 批量范圍取消請求
//先標記
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);
//再在onStop方法中取消
@Override
protected void onStop () {
super.onStop();
if (mRequestQueue != null) {
mRequestQueue.cancelAll(TAG);
}
}
注意:要謹慎嗲用cancel方法.假設這樣一個場景:你要根據請求的返回結果做下一步工作。而這步的工作在成功或者失敗的時候都要執行。那如果取消掉了請求。這段必須執行的邏輯就永遠執行不到了。
再次說明:cancel后 ,response處理程序將不會被調用
脫離newRequestQueue自己配置一個請求隊列
Volley.newRequestQueue 簡化了請求隊列的構造。但如果要自定義請求隊列就要自己配置。一個網絡請求隊列需要兩個工具:網絡執行請求的運輸,和緩存處理緩存。
Volley toolbox有標準的實現。diskbasedcache采用文件/響應緩存一一對應的方式提供一個內存索引。
BasicNetwork提供了一個基于首選的HTTP客戶端的網絡傳輸。默認是HttpUrlConnection API9一下是HttpClient
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.example.com";
// Formulate the request and handle the response.
StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
new Response.Listener<String>() {
@Override
public void onResponse(String response) {
// Do something with the response
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
// Handle error
}
});
// Add the request to the RequestQueue.
mRequestQueue.add(stringRequest);
// ...
如果支持做一次性的請求操作那用Volley.newRequestQueue就行了。然后再相應返回或者錯誤以后調用RequestQueue的stop把請求的線程池停掉就行了。
但是通常情況的場景是在app的整個運行期內都要維持這個隊列,把RequestQueue作為一個單例用。
單例模式的RequestQueue
最直接的方式就是在Application的onCreate中構建RequestQueue對象。但是這樣做并不是最好的。
最好的方式就是用靜態單例更模塊化的方式提供相同的功能
一個關鍵的概念是,所以必須實例化時使用ApplicationContext,不是一個ActivityContext。這樣是為了保證RequestQueue的生命周期和app存貨的時間是一樣的。
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);
@Override
public Bitmap getBitmap(String url) {
return cache.get(url);
}
@Override
public 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;
}
}
這個單例中發送請求的用法:
// 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);
實現自定義的請求對象
大多數請求已經準備好在工具箱中使用實現;如果響應是字符串、圖像或JSON,則可能不需要實現自定義請求。
對于需要實現自定義請求的情況,這是需要做的全部工作:
繼承Request類, 表示請求之后解析響應的類型。如果解析后的響應是String,那T就應該是String.
實現 parseNetworkResponse() 和deliverResponse()方法。
parseNetworkResponse
Response會按照指定的類型去封裝解析過的響應。
@Override
protected Response<T> parseNetworkResponse(
NetworkResponse response) {
try {
String json = new String(response.data,
HttpHeaderParser.parseCharset(response.headers));
return Response.success(gson.fromJson(json, clazz),
HttpHeaderParser.parseCacheHeaders(response));
}
// handle errors
...
}
NetworkResponse參數包含了返回的所有數據。包括byte[]形式的返回響應,HTTP狀態碼,響應頭。
注意: 實現必須返回一個Response,并包含指定類型T的相應對象、緩存數據或者一個錯誤信息,比如解析失敗等。
如果請求協議不是標準的緩存語法,可以自己構筑一個Cache.Entry
return Response.success(myDecodedObject,HttpHeaderParser.parseCacheHeaders(response));
Volley在工作線程調用parseNetworkResponse()方法。確保了昂貴的解析操作,例如將jpeg解碼成位圖,不會阻止UI線程。
deliverResponse
Volley從主線程中回調parseNetworkResponse()方法返回的對象。請求用回調接口回調回來這個對象:
protected void deliverResponse(T response) { listener.onResponse(response);
一個完整的自定義請求例子 GsonRequest
public class GsonRequest<T> extends Request<T> {
private final Gson gson = new Gson();
private final Class<T> clazz;
private final Map<String, String> headers;
private final Listener<T> listener;
/**
* Make a GET request and return a parsed object from JSON.
*
* @param url URL of the request to make
* @param clazz Relevant class object, for Gson's reflection
* @param headers Map of request headers
*/
public GsonRequest(String url, Class<T> clazz, Map<String, String> headers,
Listener<T> listener, ErrorListener errorListener) {
super(Method.GET, url, errorListener);
this.clazz = clazz;
this.headers = headers;
this.listener = listener;
}
@Override
public Map<String, String> getHeaders() throws AuthFailureError {
return headers != null ? headers : super.getHeaders();
}
@Override
protected void deliverResponse(T response) {
listener.onResponse(response);
}
@Override
protected Response<T> 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) {
return Response.error(new ParseError(e));
}
}
}
總結
以上是生活随笔為你收集整理的Volley解析(一)--Volley的使用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: web.xml中servlet配置及其含
- 下一篇: InfluxDB部署和使用