1. 程式人生 > >Volley網路請求框架解析

Volley網路請求框架解析

背景

Volley網路框架,是谷歌13開發給開發的一套網路請求載入框架,這個框架比較適合於請求資料量比較小,但是請求比較頻繁的情況下使用,對於資料量比較大的這個框架就不是很適合, 因為底層是用請求佇列的形式,因為本身比較小,不會加大App本身的大小所以很多人選擇,我們有必要了解這個網路請求框架的執行流程。

一、Volley框架的簡單使用

private void getStringRequest() {
            String url="http://api.k780.com:88/?app=phone.get&phone=13800138000&appkey=10003&sign=b59bc3ef6191eb9f747dd4e83c99f2a4&format=json"
; RequestQueue queue= Volley.newRequestQueue(this); StringRequest request=new StringRequest(url, new Response.Listener<String>() { @Override public void onResponse(String s) { Log.e("success",s); } }, new
Response.ErrorListener() { @Override public void onErrorResponse(VolleyError volleyError) { } }); queue.add(request); }

二、程式碼原始碼分析

  RequestQueue queue= Volley.newRequestQueue(this);

對應原始碼

   public static RequestQueue newRequestQueue
(Context context, BaseHttpStack stack) { BasicNetwork network; if (stack == null) { if (Build.VERSION.SDK_INT >= 9) { //如果版本小於9 network = new BasicNetwork(new HurlStack()); } else { // Prior to Gingerbread, HttpUrlConnection was unreliable. // See: http://android-developers.blogspot.com/2011/09/androids-http-clients.html // At some point in the future we'll move our minSdkVersion past Froyo and can // delete this fallback (along with all Apache HTTP code). //生成一個 String userAgent = "volley/0"; try { String packageName = context.getPackageName(); PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0); userAgent = packageName + "/" + info.versionCode; } catch (NameNotFoundException e) { } network = new BasicNetwork( new HttpClientStack(AndroidHttpClient.newInstance(userAgent))); } } else { network = new BasicNetwork(stack); } return newRequestQueue(context, network); } /** * Creates a default instance of the worker pool and calls {@link RequestQueue#start()} on it. * * @param context A {@link Context} to use for creating the cache dir. * @param stack An {@link HttpStack} to use for the network, or null for default. * @return A started {@link RequestQueue} instance. * @deprecated Use {@link #newRequestQueue(Context, BaseHttpStack)} instead to avoid depending * on Apache HTTP. This method may be removed in a future release of Volley. */ @Deprecated @SuppressWarnings("deprecation") public static RequestQueue newRequestQueue(Context context, HttpStack stack) { if (stack == null) { return newRequestQueue(context, (BaseHttpStack) null); } return newRequestQueue(context, new BasicNetwork(stack)); } private static RequestQueue newRequestQueue(Context context, Network network) { File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR); RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir), network); queue.start(); return queue; } /** * 最初始傳入的方法 */ public static RequestQueue newRequestQueue(Context context) { return newRequestQueue(context, (BaseHttpStack) null); } }

接下來我們看一下StringRequest這個類

public class StringRequest extends Request<String> {

    /** Lock to guard mListener as it is cleared on cancel() and read on delivery. */
    private final Object mLock = new Object();

    // @GuardedBy("mLock")
    private Listener<String> mListener;

    /**
     *建立一個stringRequest;
     * @param method the request {@link Method} to use
     * @param url URL to fetch the string at
     * @param listener Listener to receive the String response
     * @param errorListener Error listener, or null to ignore errors
     */
    public StringRequest(int method, String url, Listener<String> listener,
            ErrorListener errorListener) {
        super(method, url, errorListener);
        mListener = listener;
    }

    /**
     * Creates a new GET request.
     *
     * @param url URL to fetch the string at
     * @param listener Listener to receive the String response
     * @param errorListener Error listener, or null to ignore errors
     */
    public StringRequest(String url, Listener<String> listener, ErrorListener errorListener) {
        this(Method.GET, url, listener, errorListener);
    }
    //取消這個請求
    @Override
    public void cancel() {
        super.cancel();
        synchronized (mLock) {
            mListener = null;
        }
    }

    //分發響應
    @Override
    protected void deliverResponse(String response) {
        Response.Listener<String> listener;
        synchronized (mLock) {
            listener = mListener;
        }
        if (listener != null) {
            listener.onResponse(response);
        }
    }

    //解析響應
    @Override
    protected Response<String> parseNetworkResponse(NetworkResponse response) {
        String parsed;
        try {
            parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
        } catch (UnsupportedEncodingException e) {
            parsed = new String(response.data);
        }
        return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response));
    }
}
  /**
     * 開始分發佇列
     */
    public void start() {
        stop();  // Make sure any currently running dispatchers are stopped.
        // Create the cache dispatcher and start it.
        mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery);
        mCacheDispatcher.start();

        // Create network dispatchers (and corresponding threads) up to the pool size.
        for (int i = 0; i < mDispatchers.length; i++) {
            NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork,
                    mCache, mDelivery);
            mDispatchers[i] = networkDispatcher;
            networkDispatcher.start();
        }
    }

對於快取分發器

   final Request<?> request = mCacheQueue.take();
        request.addMarker("cache-queue-take");

        // If the request has been canceled, don't bother dispatching it.
        if (request.isCanceled()) {
            request.finish("cache-discard-canceled");
            return;
        }

        // Attempt to retrieve this item from cache.

        Cache.Entry entry = mCache.get(request.getCacheKey());
        if (entry == null) {
            request.addMarker("cache-miss");
            // Cache miss; send off to the network dispatcher.
            //如果快取找不到 那麼去網路下載
            if (!mWaitingRequestManager.maybeAddToWaitingRequests(request)) {
                mNetworkQueue.put(request);
            }
            return;
        }

        // If it is completely expired, just send it to the network.
        //如果有但是過期了  那麼請求放到網路佇列中
        if (entry.isExpired()) {
            request.addMarker("cache-hit-expired");
            request.setCacheEntry(entry);
            if (!mWaitingRequestManager.maybeAddToWaitingRequests(request)) {
                mNetworkQueue.put(request);
            }
            return;
        }

        // We have a cache hit; parse its data for delivery back to the request.
        //如果中 那麼解析資料
        request.addMarker("cache-hit");
        Response<?> response = request.parseNetworkResponse(
                new NetworkResponse(entry.data, entry.responseHeaders));
        request.addMarker("cache-hit-parsed");

        if (!entry.refreshNeeded()) {
            // Completely unexpired cache hit. Just deliver the response.
            mDelivery.postResponse(request, response);
        } else {
            // Soft-expired cache hit. We can deliver the cached response,
            // but we need to also send the request to the network for
            // refreshing.
            request.addMarker("cache-hit-refresh-needed");
            request.setCacheEntry(entry);
            // Mark the response as intermediate.
            response.intermediate = true;

            if (!mWaitingRequestManager.maybeAddToWaitingRequests(request)) {
                // Post the intermediate response back to the user and have
                // the delivery then forward the request along to the network.
                mDelivery.postResponse(request, response, new Runnable() {
                    @Override
                    public void run() {
                        try {
                            mNetworkQueue.put(request);
                        } catch (InterruptedException e) {
                            // Restore the interrupted status
                            Thread.currentThread().interrupt();
                        }
                    }
                });
            } else {
                // request has been added to list of waiting requests
                // to receive the network response from the first request once it returns.
                mDelivery.postResponse(request, response);
            }
        }

網路請求佇列

  private void processRequest() throws InterruptedException {
        // Take a request from the queue.
        Request<?> request = mQueue.take();//拿到一個請求

        long startTimeMs = SystemClock.elapsedRealtime();//記錄開始
        try {
            request.addMarker("network-queue-take");//新增標識

            // If the request was cancelled already, do not perform the
            // network request.
            if (request.isCanceled()) {//請求是否被取消
                request.finish("network-discard-cancelled");//
                request.notifyListenerResponseNotUsable();
                return;
            }

            addTrafficStatsTag(request);

            // Perform the network request.
            NetworkResponse networkResponse = mNetwork.performRequest(request);//拿到響應
            request.addMarker("network-http-complete");//新增標識

            // If the server returned 304 AND we delivered a response already,
            // we're done -- don't deliver a second identical response.
            if (networkResponse.notModified && request.hasHadResponseDelivered()) {
                request.finish("not-modified");
                request.notifyListenerResponseNotUsable();
                return;
            }//

            // Parse the response here on the worker thread.
            Response<?> response = request.parseNetworkResponse(networkResponse);
            request.addMarker("network-parse-complete");//解析完成

            // Write to cache if applicable.
            // TODO: Only update cache metadata instead of entire record for 304s.
            if (request.shouldCache() && response.cacheEntry != null) {//放到快取中
                mCache.put(request.getCacheKey(), response.cacheEntry);
                request.addMarker("network-cache-written");
            }

            // Post the response back.
            request.markDelivered();
            mDelivery.postResponse(request, response);
            request.notifyListenerResponseReceived(response);
        } catch (VolleyError volleyError) {
            volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs);
            parseAndDeliverNetworkError(request, volleyError);
            request.notifyListenerResponseNotUsable();
        } catch (Exception e) {
            VolleyLog.e(e, "Unhandled exception %s", e.toString());
            VolleyError volleyError = new VolleyError(e);
            volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs);
            mDelivery.postError(request, volleyError);
            request.notifyListenerResponseNotUsable();
        }
    }