Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Volley 源碼分析

Volley 源碼分析

編輯:關於Android編程

Volley基本使用

        //聲明一個請求隊列,請求隊列最好全局唯一。
        RequestQueue mQueue = Volley.newRequestQueue(context);
        //請求的錯誤回調
        Response.ErrorListener errorListener = new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError volleyError) {
                  ...
            }
        };
        //請求的正確回調
        Response.Listener listener = new Response.Listener() {
            @Override
            public void onResponse(Object o) {


            }
        };
        //封裝好的請求
        StringRequest stringRequest = new StringRequest(Request.Method.POST, url, listener, errorListener) {

                @Override
                protected Map getParams() throws AuthFailureError {
                    // TODO Auto-generated method stub
                    if (request.isEmpty())
                        return super.getParams();
                    else {
                        return request;
                    }
                }

            };
        //將封裝好的請求加入到請求隊列中去
        mQueue.add(stringRequest);


整體框架

這裡寫圖片描述

Volley整體框架如上圖所示,是一個典型的生產者消費者模式。主要可以分成三個部分,一個是封裝好的Request,包含請求的類型等等,然後將其投入到RequestQueue中,之後有一個用於分發請求的線程Dispatcher,進行網絡請求的執行和回調。下面分部分分析:<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxociAvPg0KPGgzIGlkPQ=="request">Request

這裡寫圖片描述
抽象父類Request,有多個不同種類的Request。StringRequest的構造器調用父類構造器,在Request中存儲http請求的方式,Url和失敗回調的地址。成功的回調是一個泛型接口

    public interface Listener {
        /** Called when a response is received. */
        public void onResponse(T response);
    }

這裡我們將類型參數賦值為String,然後將接口實現並存儲在StringRequest中的mListener中。在Request中另有抽象方法parseNetworkResponse和deliverResponse,子類實現,後面消費者消費Request時候,調用parseNetworkResponse解析原始的響應,然後調用deliverResponse分發給UI線程。
StringRequest的具體實現:

@Override
    protected Response 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));
    }

將網絡響應的報文體直接按字符串轉換,封裝進Response返回。

    @Override
    protected void deliverResponse(String response) {
        if (mListener != null) {
            mListener.onResponse(response);
        }
    }

然後將Respone通過設置的回調接口,調用來處理客戶端想要處理的邏輯。
這種典型的寫法啟示我們,在實現異步邏輯的時候,可以將客戶端想要的邏輯利用接口實現,然後封裝進一個實體中,當線程完成工作後調用這個實體存儲的接口實現,從而客戶端可以異步實現邏輯。

RequestQueue

大致了解了封裝的實體類Request後,來看一下生產者和消費者連接的部分RequestQueue。
調用Volley類中靜態方法newRequestQueue來實例化一個RequestQueue

    public RequestQueue(Cache cache, Network network, int threadPoolSize,
            ResponseDelivery delivery) {
        mCache = cache;
        mNetwork = network;
        mDispatchers = new NetworkDispatcher[threadPoolSize];
        mDelivery = delivery;
    }

構造器中,cache是緩存文件目錄,network中封裝了如何將Request轉化為http請求的方法performRequest,類似於策略模式。Dispatchers就是從隊列中拿出Request進行網絡請求的workerThread消費者,delivery默認值是new ExecutorDelivery(new Handler(Looper.getMainLooper())),其中的handler和UI線程的Looper相連,從而可以通過handler向UI線程的消息隊列發送消息更改UI,delivery也就是結果處理後的界面更改回調。
綜上,RequestQueue中封裝了Request轉換為網絡請求的方法,分發請求的工作線程,將結果發送給UI的傳遞者。
調用requestQueue.start()後,啟動緩存線程和網絡請求線程,主要分析網絡請求部分:

        for (int i = 0; i < mDispatchers.length; i++) {
            NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork,
                    mCache, mDelivery);
            mDispatchers[i] = networkDispatcher;
            networkDispatcher.start();
        }

mDispachers是一個數組,類似線程池存儲著工人線程。NetworkDispatcher是worker thread,

    public void quit() {
        mQuit = true;
        interrupt();
    }

quit方法通過interrupt和標志位中斷一個線程。

@Override
    public void run() {
        //設置當前線程為後台線程,減少對於UI線程渲染的影響
        Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
        Request request;
        while (true) {
            long startTimeMs = SystemClock.elapsedRealtime();
            // release previous request object to avoid leaking request object when mQueue is drained.
            request = null;
            try {
                // Take a request from the queue.
                request = mQueue.take();
            } catch (InterruptedException e) {
                // We may have been interrupted because it was time to quit.
                //檢查標志位,看隊列是否結束
                if (mQuit) {
                    return;
                }
                continue;
            }

            try {

                // If the request was cancelled already, do not perform the
                // network request.
                if (request.isCanceled()) {
                    request.finish("network-discard-cancelled");
                    continue;
                }


                // 這裡調用網絡請求策略network,將Request轉化為網絡請求處理。獲得響應封裝。
                NetworkResponse networkResponse = mNetwork.performRequest(request);

                //304緩存處理。沒有修改,不進行http請求維持原狀。
                if (networkResponse.notModified && request.hasHadResponseDelivered()) {
                    request.finish("not-modified");
                    continue;
                }

                // 將原始的網絡請求解析,這裡是按照StringRequest的方式解析。
                Response response = request.parseNetworkResponse(networkResponse);

                //緩存相關
                if (request.shouldCache() && response.cacheEntry != null) {
                    mCache.put(request.getCacheKey(), response.cacheEntry);
                    request.addMarker("network-cache-written");
                }

                // delivery,分發更改UI
                request.markDelivered();
                mDelivery.postResponse(request, response);
            } catch (VolleyError volleyError) {
                volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs);
                parseAndDeliverNetworkError(request, volleyError);
            } 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);
            }
        }
    }

Delivery

分發部分的實現

    public void postResponse(Request request, Response response, Runnable runnable) {
        request.markDelivered();
        request.addMarker("post-response");
        mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, runnable));
    }

其中

        mResponsePoster = new Executor() {
            @Override
            public void execute(Runnable command) {
                handler.post(command);
            }
        };

ResponseDeliveryRunnable是給UI線程的Handler發送的Runnable,也就是說這部分是執行在UI線程上的,其中邏輯部分:

@SuppressWarnings("unchecked")
        @Override
        public void run() {
            // If this request has canceled, finish it and don't deliver.
            if (mRequest.isCanceled()) {
                mRequest.finish("canceled-at-delivery");
                return;
            }

            // 調用我們定義的Request中的listener回調
            if (mResponse.isSuccess()) {
                mRequest.deliverResponse(mResponse.result);
            } else {
                mRequest.deliverError(mResponse.error);
            }

            // If this is an intermediate response, add a marker, otherwise we're done
            // and the request can be finished.
            if (mResponse.intermediate) {
                mRequest.addMarker("intermediate-response");
            } else {
                mRequest.finish("done");
            }

            // If we have been provided a post-delivery runnable, run it.
            if (mRunnable != null) {
                mRunnable.run();
            }
       }

可以看在,最初在Request中封裝的更改UI的listener,在mRequest.deliverResponse(mResponse.result); 被異步調用並執行,並且通過ExecutorDelivery確保在UI線程中執行,ExecutorDelivery類似命令模式,dispatcher負責網絡部分,Delivery負責UI部分,確保收到的每個Request響應的回調執行在UI線程中。


總結

作為生產者-消費者模式,客戶端可以將網絡請求的處理方式,獲取響應後的處理邏輯封裝進Request,然後放進RequestQueue中。對於一個全局的RequestQueue,維護一個工作線程池,利用多個線程從隊列中去除Request去執行網絡請求,根據Request中封裝的網絡請求方法獲取Response後,將結果給Delivery。然後通過Delivery分發給UI線程,調用Request中更新的UI處理邏輯。
對比傳統的通過新建線程實現網絡請求的方式,volley采用的方式不僅邏輯清晰、易於管理,同時將線程維護、UI更新這部分不易發生變化的工作封裝,用戶也可通過繼承Request實現擴展,增強了可維護性。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved