Android中關於Volley的使用(十)對Request和Reponse的認識

來源:互聯網
上載者:User

標籤: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來進行處理。

結束。


相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.