標籤:android volley request response 源碼
我們知道,在網路Http通訊中,一定會有一個Request,同樣的,也一定會有一個Response,而我們在Volley中利用RequestQueue來添加請求之前,一定會先建立一個Request對象,比如StringRequest,JsonObjectRequest和ImageRequest等,如下分別是前面Demo中的JsonRequest和ImageRequest:
JsonObjectRequest:
public JsonObjectRequest(String url, JSONObject jsonRequest, Listener<JSONObject> listener, ErrorListener errorListener) {
ImageRequest:
public ImageRequest(String url, Response.Listener<Bitmap> listener, int maxWidth, int maxHeight, Config decodeConfig, Response.ErrorListener errorListener)
Volley中提供了一個基礎的Request抽象類別,如下:
public abstract class Request<T> implements Comparable<Request<T>> {
在這個類中,定義了一些請求中基本的參數變數,如
Method:
/** * Request method of this request. Currently supports GET, POST, PUT, DELETE, HEAD, OPTIONS, * TRACE, and PATCH. */ private final int mMethod;
它的值如下:
/** * Supported request methods. */ public interface Method { int DEPRECATED_GET_OR_POST = -1; int GET = 0; int POST = 1; int PUT = 2; int DELETE = 3; int HEAD = 4; int OPTIONS = 5; int TRACE = 6; int PATCH = 7; }
請求中的Url:
/** URL of this request. */ private final String mUrl;
一個ErroListener,
/** Listener interface for errors. */ private final Response.ErrorListener mErrorListener;
還有其它的一些參數,如shouldCache(是否需要緩衝),tag(分類標籤)等,而在Request中還提供了下面兩個抽象方法,必須由子類實現:
/** * Subclasses must implement this to parse the raw network response * and return an appropriate response type. This method will be * called from a worker thread. The response will not be delivered * if you return null. * @param response Response from the network * @return The parsed response, or null in the case of an error */ abstract protected Response<T> parseNetworkResponse(NetworkResponse response);
/** * Subclasses must implement this to perform delivery of the parsed * response to their listeners. The given response is guaranteed to * be non-null; responses that fail to parse are not delivered. * @param response The parsed response returned by * {@link #parseNetworkResponse(NetworkResponse)} */ abstract protected void deliverResponse(T response);
每一個子類都必須實現兩個方法,
1)parseNetworkResponse
當從網路中擷取到Response的時候,怎麼去解析對應的請求,這是由各個對應的Request去分析的,比如JsonObjectRequest中:
@Override protected Response<JSONObject> parseNetworkResponse(NetworkResponse response) { try { String jsonString = new String(response.data, HttpHeaderParser.parseCharset(response.headers)); return Response.success(new JSONObject(jsonString), HttpHeaderParser.parseCacheHeaders(response)); } catch (UnsupportedEncodingException e) { return Response.error(new ParseError(e)); } catch (JSONException je) { return Response.error(new ParseError(je)); } }
再比如ImageRequest中的:
@Override protected Response<Bitmap> parseNetworkResponse(NetworkResponse response) { // Serialize all decode on a global lock to reduce concurrent heap usage. synchronized (sDecodeLock) { try { return doParse(response); } catch (OutOfMemoryError e) { VolleyLog.e("Caught OOM for %d byte image, url=%s", response.data.length, getUrl()); return Response.error(new ParseError(e)); } } }
而在doParse中,其實是對圖片進行處理,如下:
private Response<Bitmap> doParse(NetworkResponse response) { byte[] data = response.data; BitmapFactory.Options decodeOptions = new BitmapFactory.Options(); Bitmap bitmap = null; if (mMaxWidth == 0 && mMaxHeight == 0) { decodeOptions.inPreferredConfig = mDecodeConfig; bitmap = BitmapFactory.decodeByteArray(data, 0, data.length, decodeOptions); } else { // If we have to resize this image, first get the natural bounds. decodeOptions.inJustDecodeBounds = true; BitmapFactory.decodeByteArray(data, 0, data.length, decodeOptions); int actualWidth = decodeOptions.outWidth; int actualHeight = decodeOptions.outHeight; // Then compute the dimensions we would ideally like to decode to. int desiredWidth = getResizedDimension(mMaxWidth, mMaxHeight, actualWidth, actualHeight); int desiredHeight = getResizedDimension(mMaxHeight, mMaxWidth, actualHeight, actualWidth); // Decode to the nearest power of two scaling factor. decodeOptions.inJustDecodeBounds = false; // TODO(ficus): Do we need this or is it okay since API 8 doesn‘t support it? // decodeOptions.inPreferQualityOverSpeed = PREFER_QUALITY_OVER_SPEED; decodeOptions.inSampleSize = findBestSampleSize(actualWidth, actualHeight, desiredWidth, desiredHeight); Bitmap tempBitmap = BitmapFactory.decodeByteArray(data, 0, data.length, decodeOptions); // If necessary, scale down to the maximal acceptable size. if (tempBitmap != null && (tempBitmap.getWidth() > desiredWidth || tempBitmap.getHeight() > desiredHeight)) { bitmap = Bitmap.createScaledBitmap(tempBitmap, desiredWidth, desiredHeight, true); tempBitmap.recycle(); } else { bitmap = tempBitmap; } } if (bitmap == null) { return Response.error(new ParseError(response)); } else { return Response.success(bitmap, HttpHeaderParser.parseCacheHeaders(response)); } }
所以,如果我們自訂一個Request的話,我們就要去實現我們自己的邏輯,比如是擷取視頻的話,就會去對資料進行解碼等。
在上面的方法實現中,我們可以看到,最後都是通過Response.success方法返回一個Response對象,而這個Response對象是怎麼用的呢,就要看下面deliverResponse方法了。
2)deliverResponse
在NetworkDispatcher線程中,當從網路中擷取到資料,並通過請求的parseNetworkResponse方法解析之後,會返回一個Reponse對象,這個時候,就會調用Executor來將這個請求post回主線程,如下:
mDelivery.postResponse(request, response);
而mDelivery中的postResponse方法其實是另起一個新線程來調用Request的deliverResponse方法,在ExecutorDelivery類中:
public void postResponse(Request<?> request, Response<?> response, Runnable runnable) { request.markDelivered(); request.addMarker("post-response"); mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, runnable)); }
ResponseDeliveryRunnable類的run方法中,我們可以看到:
// Deliver a normal response or error, depending. if (mResponse.isSuccess()) { mRequest.deliverResponse(mResponse.result); } else { mRequest.deliverError(mResponse.error); }
那我們看看StringRequest和ImageRequest中的deliverResponse方法:
private final Response.Listener<Bitmap> mListener;...@Override protected void deliverResponse(Bitmap response) { mListener.onResponse(response); }
我們可以看到,其實都是調用一個Response.Listener類的onResponse方法,而其實這個Listener,則是我們在建立請求的時候才實現,並傳進來的,如前面Demo中建立JsonObjectRequest和ImageRequest的時候:
ImageRequest imgRequest = new ImageRequest(imgUrl,new Response.Listener<Bitmap>() {@Overridepublic void onResponse(Bitmap arg0) {// TODO Auto-generated method stubimageView.setImageBitmap(arg0);}}, 100, 100, Config.ARGB_8888, new ErrorListener() {@Overridepublic void onErrorResponse(VolleyError arg0) {imageView.setImageResource(R.drawable.ic_launcher);}});
如上面new Reponse.Listener方法中的實現,很顯然,之所以這麼做的原因在於只有調用者才知道怎麼去處理Request解析過的資料。
而從這裡,我們也可以知道在Reponse類中,就會定義這麼一個介面,如下,是Volley中Response類的定義:
public class Response<T> { /** Callback interface for delivering parsed responses. */ public interface Listener<T> { /** Called when a response is received. */ public void onResponse(T response); }
而除了這個介面的定義,還有一個ErrorListener介面的定義就不列出來了。而除此之外,Response類中就存放了CacheEntry等資訊,相對來說,因為定義了這樣的Listener介面,Response類是相對比較簡單的。
好了,到這裡,總結一下:
1)建立一個Request的時候,會同時設定一個Response.Listener作為請求的一個參數變數,之後調用RequestQueue的add方法將其添加到Queue。
2)在Queue中的請求會由NetworkDispatcher去跟網路進行通訊(如果有緩衝的時候,就是CacheDispatcher)。
3)當請求結果回來的時候,Request會首先調用parseNetworkResponse方法根據不同的請求類型,如Json,Image等進行不同的處理。
4)當Request分析完之後,得到的Reponse對象,就會由ResponseDelivery類新起一個線程,調用1)步中的Listener來進行處理。
結束。