Volley實(shí)現(xiàn)脈絡(luò)學(xué)習(xí)

Volley 是 Google 推出的 Android 異步網(wǎng)絡(luò)請(qǐng)求框架和圖片加載框架。在 Google I/O 2013 大會(huì)上發(fā)布的,現(xiàn)在連android系統(tǒng)中內(nèi)部也是使用了Volley作為其網(wǎng)絡(luò)的請(qǐng)求框架,谷歌出品,必屬精品,所以有必要進(jìn)行一次梳理其實(shí)現(xiàn)的總體過(guò)程,學(xué)習(xí)其設(shè)計(jì)框架的思路也是必要的(文章適合知道基本使用Volley的同學(xué)觀看)。


<h3>Volley</h3>

一般我們都會(huì)在app初始化的時(shí)候調(diào)用如下代碼進(jìn)行初始化Volley,下面就從該方法當(dāng)做閱讀入口進(jìn)行逐一跟蹤:

mRequestQueue =  Volley.newRequestQueue(this); 

在調(diào)用Volley.newRequestQueue(this)時(shí),最終調(diào)用到如下代碼:

 /**
     * Creates a default instance of the worker pool and calls {@link RequestQueue#start()} on it.
     * You may set a maximum size of the disk cache in bytes.
     *HttpStack是用來(lái)進(jìn)行網(wǎng)絡(luò)請(qǐng)求封裝的類(lèi),傳入null代表默認(rèn)
     *maxDiskCacheBytes為最大磁盤(pán)緩存,傳入-1使用默認(rèn)大小
     */
    public static RequestQueue newRequestQueue(Context context, HttpStack stack, int maxDiskCacheBytes) {
      //構(gòu)造緩存區(qū)域
        File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR);

        String userAgent = "volley/0";
        try {
            String packageName = context.getPackageName();
            PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0);
            userAgent = packageName + "/" + info.versionCode;
        } catch (NameNotFoundException e) {
        }
        //我們可以傳入okttp來(lái)充當(dāng)我們的httpStack
        if (stack == null) {
          //使用Volley默認(rèn)封裝的stack,依靠android版本來(lái)決定使用不同的connection來(lái)進(jìn)行網(wǎng)絡(luò)請(qǐng)求
            if (Build.VERSION.SDK_INT >= 9) {
                stack = new HurlStack();
            } else {
                // Prior to Gingerbread, HttpUrlConnection was unreliable.
                // See: http://android-developers.blogspot.com/2011/09/androids-http-clients.html
                stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));
            }
        }

        Network network = new BasicNetwork(stack);
        
        RequestQueue queue;
        if (maxDiskCacheBytes <= -1)
        {
            // No maximum size specified
            queue = new RequestQueue(new DiskBasedCache(cacheDir), network);
        }
        else
        {
            // Disk cache size specified
            queue = new RequestQueue(new DiskBasedCache(cacheDir, maxDiskCacheBytes), network);
        }

        queue.start();

        return queue;
    }

在newRequestQueue?方法中進(jìn)行了相關(guān)必要參數(shù)的初始化的工作,其中包括:

  • 緩存區(qū)域的初始化
  • HttpStack的初始化
  • Network的初始化
  • RequestQueue的初始化,最終調(diào)用其start()方法

Stack 詳解

在Volley中如果沒(méi)有傳遞任何HttpStack則會(huì)使用了兩種stack來(lái)進(jìn)行不同android版本(SDK_INT >= 9?HurlStack:HttpClientStack)的適配工作:HurlStack和HttpClientStack,兩種stack都實(shí)現(xiàn)了HttpStack接口,接口定義如下:

public interface HttpStack {
    //請(qǐng)求處理方法
    public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)
        throws IOException, AuthFailureError;

}

在接口中定義performRequest方法,在其子類(lèi)中實(shí)現(xiàn)了對(duì)于http請(qǐng)求的封裝的操作,以此來(lái)查看對(duì)應(yīng)實(shí)現(xiàn)子類(lèi)的performRequest方法。

在HurlStack中關(guān)于performRequest(…)的實(shí)現(xiàn):

@Override
    public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)
            throws IOException, AuthFailureError {
        String url = request.getUrl();
      //存放請(qǐng)求頭
        HashMap<String, String> map = new HashMap<String, String>();
        map.putAll(request.getHeaders());
        map.putAll(additionalHeaders);
      //是否重寫(xiě)url
        if (mUrlRewriter != null) {
            String rewritten = mUrlRewriter.rewriteUrl(url);
            if (rewritten == null) {
                throw new IOException("URL blocked by rewriter: " + url);
            }
            url = rewritten;
        }
        URL parsedUrl = new URL(url);
      //使用后HttpURLConnection進(jìn)行網(wǎng)絡(luò)請(qǐng)求
        HttpURLConnection connection = openConnection(parsedUrl, request);
        for (String headerName : map.keySet()) {
            connection.addRequestProperty(headerName, map.get(headerName));
        }
      //設(shè)置請(qǐng)求方法:GET ,POST, ect
        setConnectionParametersForRequest(connection, request);
        // Initialize HttpResponse with data from the HttpURLConnection.
        ProtocolVersion protocolVersion = new ProtocolVersion("HTTP", 1, 1);
        int responseCode = connection.getResponseCode();
        if (responseCode == -1) {
            // -1 is returned by getResponseCode() if the response code could not be retrieved.
            // Signal to the caller that something was wrong with the connection.
            throw new IOException("Could not retrieve response code from HttpUrlConnection.");
        }
        StatusLine responseStatus = new BasicStatusLine(protocolVersion,
                connection.getResponseCode(), connection.getResponseMessage());
        BasicHttpResponse response = new BasicHttpResponse(responseStatus);
        //將返回的數(shù)據(jù)流寫(xiě)入response
        response.setEntity(entityFromConnection(connection));
        //獲取返回的請(qǐng)求頭
        for (Entry<String, List<String>> header : connection.getHeaderFields().entrySet()) {
            if (header.getKey() != null) {
                Header h = new BasicHeader(header.getKey(), header.getValue().get(0));
                response.addHeader(h);
            }
        }
        return response;
    }

HurlStack使用HttpURLConnection進(jìn)行Http請(qǐng)求的過(guò)程,步驟是基本的網(wǎng)絡(luò)請(qǐng)求的過(guò)程,設(shè)置請(qǐng)求頭->包裝Url->打開(kāi)連接->設(shè)置請(qǐng)求方法->獲取數(shù)據(jù)已經(jīng)請(qǐng)求狀態(tài)->將數(shù)據(jù)流存入HttpResponse,最終返回一個(gè)HttpResponse。

HttpClientStack中關(guān)于performRequest(…)的實(shí)現(xiàn):

@Override
    public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)
            throws IOException, AuthFailureError {
        //構(gòu)造請(qǐng)求參數(shù)
        HttpUriRequest httpRequest = createHttpRequest(request, additionalHeaders);
        //添加請(qǐng)求頭
        addHeaders(httpRequest, additionalHeaders);
        addHeaders(httpRequest, request.getHeaders());
        onPrepareRequest(httpRequest);
        HttpParams httpParams = httpRequest.getParams();
        int timeoutMs = request.getTimeoutMs();
        // TODO: Reevaluate this connection timeout based on more wide-scale
        // data collection and possibly different for wifi vs. 3G.
        HttpConnectionParams.setConnectionTimeout(httpParams, 5000);
        HttpConnectionParams.setSoTimeout(httpParams, timeoutMs);
        return mClient.execute(httpRequest);
    }

HttpClientStack?執(zhí)行的大體過(guò)程與HurlStack基本上一致,通過(guò)一系列操作最終調(diào)用AndroidHttpClient.execute(httpRequest)返回一個(gè)HttpResponse。

HttpStack封裝了http請(qǐng)求的過(guò)程,并且只管http請(qǐng)求,滿(mǎn)足設(shè)計(jì)模式中單一責(zé)任的原則,并且向外提供接口HttpStack方便使用者定制自身的HttpStack類(lèi)來(lái)進(jìn)行請(qǐng)求的過(guò)程,如:可以用OkhttpClient來(lái)進(jìn)行http請(qǐng)求的過(guò)程,這對(duì)于Volley的整個(gè)流程是不受影響。


Network

public interface Network {
    /**
     * Performs the specified request.
     * @param request Request to process
     * @return A {@link NetworkResponse} with data and caching metadata; will never be null
     * @throws VolleyError on errors
     */
    public NetworkResponse performRequest(Request<?> request) throws VolleyError;
}

Network接口中定義了performRequest用于接收一個(gè)具體的Request請(qǐng)求,其實(shí)現(xiàn)類(lèi)是BasicNetwork,我們直接查看performRequest方法:

@Override
    public NetworkResponse performRequest(Request<?> request) throws VolleyError {
        long requestStart = SystemClock.elapsedRealtime();
        //死循環(huán)
        while (true) {
            HttpResponse httpResponse = null;
            byte[] responseContents = null;
            Map<String, String> responseHeaders = Collections.emptyMap();
            try {
                // Gather headers.
                Map<String, String> headers = new HashMap<String, String>();
                addCacheHeaders(headers, request.getCacheEntry());
                //通過(guò)HttpStack獲得HttpResponse
                httpResponse = mHttpStack.performRequest(request, headers);
                StatusLine statusLine = httpResponse.getStatusLine();
                int statusCode = statusLine.getStatusCode();
                //返回的請(qǐng)求頭
                responseHeaders = convertHeaders(httpResponse.getAllHeaders());
                //請(qǐng)求返回的狀態(tài)碼處理
                if (statusCode == HttpStatus.SC_NOT_MODIFIED) {
                    Entry entry = request.getCacheEntry();
                    if (entry == null) {
                        return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED, null,
                                responseHeaders, true,
                                SystemClock.elapsedRealtime() - requestStart);
                    }

                    entry.responseHeaders.putAll(responseHeaders);
                    return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED, entry.data,
                            entry.responseHeaders, true,
                            SystemClock.elapsedRealtime() - requestStart);
                }
                
                // Handle moved resources
                if (statusCode == HttpStatus.SC_MOVED_PERMANENTLY || statusCode == HttpStatus.SC_MOVED_TEMPORARILY) {
                    String newUrl = responseHeaders.get("Location");
                    request.setRedirectUrl(newUrl);
                }

                // Some responses such as 204s do not have content.  We must check.
                if (httpResponse.getEntity() != null) {
                  responseContents = entityToBytes(httpResponse.getEntity());
                } else {
                  // Add 0 byte response as a way of honestly representing a
                  // no-content request.
                  responseContents = new byte[0];
                }

                // if the request is slow, log it.
                long requestLifetime = SystemClock.elapsedRealtime() - requestStart;
                logSlowRequests(requestLifetime, request, responseContents, statusLine);

                if (statusCode < 200 || statusCode > 299) {
                    throw new IOException();
                }
                return new NetworkResponse(statusCode, responseContents, responseHeaders, false,
                        SystemClock.elapsedRealtime() - requestStart);
                ...
                int statusCode = 0;
                NetworkResponse networkResponse = null;
                if (httpResponse != null) {
                    statusCode = httpResponse.getStatusLine().getStatusCode();
                } else {
                    throw new NoConnectionError(e);
                }
                if (statusCode == HttpStatus.SC_MOVED_PERMANENTLY || 
                        statusCode == HttpStatus.SC_MOVED_TEMPORARILY) {
                    VolleyLog.e("Request at %s has been redirected to %s", request.getOriginUrl(), request.getUrl());
                } else {
                    VolleyLog.e("Unexpected response code %d for %s", statusCode, request.getUrl());
                }
                if (responseContents != null) {
                    networkResponse = new NetworkResponse(statusCode, responseContents,
                            responseHeaders, false, SystemClock.elapsedRealtime() - requestStart);
                    ...
            }
        }
    }

在BasicNetwork中,我們可以看到其通過(guò)寫(xiě)了一個(gè)死循環(huán)來(lái)保證重復(fù)請(qǐng)求的操作直到報(bào)錯(cuò)或者返回結(jié)果,在其中他會(huì)調(diào)用mHttpStack.performRequest(request, headers)來(lái)獲得一個(gè)HttpResponse,調(diào)用entityToBytes()將entity轉(zhuǎn)換成一個(gè)字節(jié)數(shù)組,并且獲取相關(guān)參數(shù)(header,statusCode .etc)去進(jìn)一步的構(gòu)造出一個(gè)NetworkResponse,并且返回:

    public NetworkResponse(int statusCode, byte[] data, Map<String, String> headers,
            boolean notModified, long networkTimeMs) {
        this.statusCode = statusCode;
        this.data = data;
        this.headers = headers;
        this.notModified = notModified;
        this.networkTimeMs = networkTimeMs;
    }

    public NetworkResponse(int statusCode, byte[] data, Map<String, String> headers,
            boolean notModified) {
        this(statusCode, data, headers, notModified, 0);
    }

    public NetworkResponse(byte[] data) {
        this(HttpStatus.SC_OK, data, Collections.<String, String>emptyMap(), false, 0);
    }

    public NetworkResponse(byte[] data, Map<String, String> headers) {
        this(HttpStatus.SC_OK, data, headers, false, 0);
    }

    /**Http狀態(tài)碼 */
    public final int statusCode;

    /**網(wǎng)絡(luò)請(qǐng)求返回的字節(jié)數(shù)據(jù) */
    public final byte[] data;

    /**返回的請(qǐng)求頭 */
    public final Map<String, String> headers;

    /** 是否返回的304的狀態(tài)碼*/
    public final boolean notModified;

    /** 請(qǐng)求耗時(shí). */
    public final long networkTimeMs;

RequestQueue

RequestQueue是一個(gè)請(qǐng)求隊(duì)列,Volley將所有Request請(qǐng)求維護(hù)在此請(qǐng)求對(duì)列當(dāng)中,內(nèi)部有兩個(gè)對(duì)應(yīng)緩存和網(wǎng)絡(luò)的請(qǐng)求阻塞隊(duì)列來(lái)對(duì)Request進(jìn)行維護(hù),并且通過(guò)不同的Dispatcher(extends Thread)進(jìn)行進(jìn)一步的請(qǐng)求結(jié)果的處理,主要代碼如下:

public class RequestQueue {

    /** 所有請(qǐng)求完成后的回調(diào) */
    public static interface RequestFinishedListener<T> {
        /** Called when a request has finished processing. */
        public void onRequestFinished(Request<T> request);
    }
    ...
    //等待請(qǐng)求的Request,如果一個(gè)請(qǐng)求可以進(jìn)行緩存,則后續(xù)的相同CacheKey的請(qǐng)求,將進(jìn)入此等待隊(duì)列。
    private final Map<String, Queue<Request<?>>> mWaitingRequests =
            new HashMap<String, Queue<Request<?>>>();
    //當(dāng)前請(qǐng)求以及未完成的請(qǐng)求
    private final Set<Request<?>> mCurrentRequests = new HashSet<Request<?>>();
    /** 緩存請(qǐng)求阻塞隊(duì)列 */
    private final PriorityBlockingQueue<Request<?>> mCacheQueue =
        new PriorityBlockingQueue<Request<?>>();
    /** 網(wǎng)絡(luò)請(qǐng)求阻塞隊(duì)列 */
    private final PriorityBlockingQueue<Request<?>> mNetworkQueue =
        new PriorityBlockingQueue<Request<?>>();
    //網(wǎng)絡(luò)請(qǐng)求線程池大小
    private static final int DEFAULT_NETWORK_THREAD_POOL_SIZE = 4;
    ...
      
    //網(wǎng)絡(luò)dispatcher數(shù)組
    private NetworkDispatcher[] mDispatchers;

    //緩存dispatcher
    private CacheDispatcher mCacheDispatcher;
    //Request完成listener
    private List<RequestFinishedListener> mFinishedListeners =
            new ArrayList<RequestFinishedListener>();

    public RequestQueue(Cache cache, Network network, int threadPoolSize,
            ResponseDelivery delivery) {
        mCache = cache;
        mNetwork = network;
        //初始化網(wǎng)絡(luò)Dispatcher
        mDispatchers = new NetworkDispatcher[threadPoolSize];
        mDelivery = delivery;
    }
    /**
     * start()方法中啟動(dòng)了緩存dispatcher跟網(wǎng)絡(luò)請(qǐng)求dispatcher,用來(lái)處理數(shù)據(jù)請(qǐng)求,
     * 如果緩存中有數(shù)據(jù),則直接在緩存中獲取數(shù)據(jù),緩存中沒(méi)有數(shù)據(jù)則從網(wǎng)絡(luò)中獲取數(shù)據(jù)。
     */
    public void start() {
        stop();  // Make sure any currently running dispatchers are stopped.
        // 啟動(dòng)緩存請(qǐng)求隊(duì)列
        mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery);
        mCacheDispatcher.start();

        // Create network dispatchers (and corresponding threads) up to the pool size.
        //創(chuàng)造網(wǎng)絡(luò)請(qǐng)求隊(duì)列
        for (int i = 0; i < mDispatchers.length; i++) {
            NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork,
                    mCache, mDelivery);
            mDispatchers[i] = networkDispatcher;
            networkDispatcher.start();
        }
    }
    ...

    /**
     * 添加新的請(qǐng)求到請(qǐng)求對(duì)列當(dāng)中
     */
    public <T> Request<T> add(Request<T> request) {
        ...
    }

    ...
    <T> void finish(Request<T> request) {
        // Remove from the set of requests currently being processed.
        synchronized (mCurrentRequests) {
            mCurrentRequests.remove(request);
        }
        synchronized (mFinishedListeners) {
          for (RequestFinishedListener<T> listener : mFinishedListeners) {
            listener.onRequestFinished(request);
          }
        }

        if (request.shouldCache()) {
            synchronized (mWaitingRequests) {
                String cacheKey = request.getCacheKey();
                Queue<Request<?>> waitingRequests = mWaitingRequests.remove(cacheKey);
                if (waitingRequests != null) {
                    mCacheQueue.addAll(waitingRequests);
                }
            }
        }
    }

    ....
}

RequestQueue是Volley中最核心的類(lèi),掌管著所有request的請(qǐng)求和調(diào)度的過(guò)程,可以說(shuō)是一個(gè)中轉(zhuǎn)器的作用,我們從剛開(kāi)始的start()方法看起:

/**
     * start()方法中啟動(dòng)了緩存dispatcher跟網(wǎng)絡(luò)請(qǐng)求dispatcher,用來(lái)處理數(shù)據(jù)請(qǐng)求,
     * 如果緩存中有數(shù)據(jù),則直接在緩存中獲取數(shù)據(jù),緩存中沒(méi)有數(shù)據(jù)則從網(wǎng)絡(luò)中獲取數(shù)據(jù)。
     */
    public void start() {
        stop();  // Make sure any currently running dispatchers are stopped.
        // 啟動(dòng)緩存請(qǐng)求隊(duì)列
        mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery);
        mCacheDispatcher.start();

        //創(chuàng)造網(wǎng)絡(luò)請(qǐng)求隊(duì)列
        for (int i = 0; i < mDispatchers.length; i++) {
            NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork,
                    mCache, mDelivery);
            mDispatchers[i] = networkDispatcher;
            networkDispatcher.start();
        }
    }

在調(diào)用start()時(shí)候,主要做了兩件事情:

  • 調(diào)用stop()終止所有的dispatcher
  • 初始化所有的dispatcher,并且start(),dispatcher都是繼承于Thread的類(lèi)

一般我們進(jìn)行請(qǐng)求時(shí)候,都是使用的add(Request)方法來(lái)進(jìn)行,所以接下來(lái)就查看一下這個(gè)方法的實(shí)現(xiàn)過(guò)程:

 /**
     * 添加新的請(qǐng)求到請(qǐng)求對(duì)列當(dāng)中
     */
    public <T> Request<T> add(Request<T> request) {
        // 設(shè)置對(duì)應(yīng)關(guān)聯(lián)
        request.setRequestQueue(this);
        //添加到CurrentRequests中
        synchronized (mCurrentRequests) {
            mCurrentRequests.add(request);
        }

        // 按添加到請(qǐng)求隊(duì)列的順序請(qǐng)求數(shù)據(jù)
        request.setSequence(getSequenceNumber());
        //添加標(biāo)志
        request.addMarker("add-to-queue");
        //當(dāng)前request是否有緩存過(guò),沒(méi)有直接加入到網(wǎng)絡(luò)請(qǐng)求隊(duì)列中
        if (!request.shouldCache()) {
            mNetworkQueue.add(request);
            return request;
        }

        synchronized (mWaitingRequests) {
            //得到緩存key(該key為medthod+url的單一key)
            String cacheKey = request.getCacheKey();
            //是否包含該緩存key
            if (mWaitingRequests.containsKey(cacheKey)) {
                // There is already a request in flight. Queue up.
                Queue<Request<?>> stagedRequests = mWaitingRequests.get(cacheKey);
                if (stagedRequests == null) {
                    stagedRequests = new LinkedList<Request<?>>();
                }
                stagedRequests.add(request);
                mWaitingRequests.put(cacheKey, stagedRequests);
                if (VolleyLog.DEBUG) {
                    VolleyLog.v("Request for cacheKey=%s is in flight, putting on hold.", cacheKey);
                }
            } else {
                // Insert 'null' queue for this cacheKey, indicating there is now a request in
                // flight.
                mWaitingRequests.put(cacheKey, null);
                mCacheQueue.add(request);
            }
            return request;
        }
    }

在add()方法中主要的過(guò)程如圖所示:

reuqestqueue.add()

主要實(shí)現(xiàn)思路如下:

  1. 添加到mCurrentRequests中,mCurrentRequests當(dāng)前請(qǐng)求以及未完成的請(qǐng)求的set,所有通過(guò)add()進(jìn)來(lái)的都會(huì)加入到?此set的當(dāng)中。
  2. 通過(guò)request.shouldCache()來(lái)判斷是否需要緩存request,如果不需要?jiǎng)t直接加入到網(wǎng)絡(luò)請(qǐng)求隊(duì)列當(dāng)中,return;如果需要緩存當(dāng)前request則判斷mWaitingRequests是否包含了該request的CacheKey的setKey,如果有,則加入相同的隊(duì)列當(dāng)中,則put到mWaitingRequests當(dāng)中,如果沒(méi)有包含了該request的CacheKey的setKey,置空與當(dāng)前request的相同的queue(mWaitingRequests.put(cacheKey, null)),然后把request加入到緩存請(qǐng)求對(duì)列當(dāng)中。

add()方法中主要是為了找到request的存放地,是網(wǎng)絡(luò)請(qǐng)求隊(duì)列還是緩存請(qǐng)求隊(duì)列,在判斷是否加入到緩存請(qǐng)求隊(duì)列時(shí)維護(hù)了一個(gè)mWaitingRequests集合來(lái)管理相同的請(qǐng)求,如果cacheKey相同,則不會(huì)加入到任何請(qǐng)對(duì)隊(duì)列當(dāng)中,然后加入到mWaitingRequests存有相同SetKey的SetValue中,掛起。


<h4>Dispatcher</h4>

返回RequestQueue.start()中,這里會(huì)將CacheDispatcher和NetworkDispatchers啟動(dòng),兩種Dispatcher共同繼承于Thread來(lái)處理延時(shí)操作--網(wǎng)絡(luò)請(qǐng)求和緩存請(qǐng)求的過(guò)程,這里只詳細(xì)講述CacheDispatcher的run()過(guò)程,NetworkDispatchers只以簡(jiǎn)述的形式講述。

CacheDispatcher在run方法中寫(xiě)死一個(gè)無(wú)限循環(huán),可以類(lèi)比成handler機(jī)制中的Looper.loop()的設(shè)計(jì)思路,不斷的輪訓(xùn)緩存隊(duì)列(mCacheQueue),從中取出request將其傳遞給mDelivery來(lái)進(jìn)行處理。

@Override
    public void run() {
        //設(shè)置線程優(yōu)先級(jí)
        Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);

        // 初始化緩存相關(guān)參數(shù)
        mCache.initialize();

        while (true) {
            try {
                //從mCacheQueue取緩存
                final Request<?> request = mCacheQueue.take();
                //添加緩存過(guò)的標(biāo)記
                request.addMarker("cache-queue-take");

                // 當(dāng)前request是否取消了
                if (request.isCanceled()) {
                    request.finish("cache-discard-canceled");
                    continue;
                }

                // 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.
                    mNetworkQueue.put(request);
                    continue;
                }

                // If it is completely expired, just send it to the network.
                if (entry.isExpired()) {
                    request.addMarker("cache-hit-expired");
                    request.setCacheEntry(entry);
                    mNetworkQueue.put(request);
                    continue;
                }

                // 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");
                //緩存數(shù)據(jù)是否需要更新
                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;

                    // 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) {
                                // Not much we can do about this.
                            }
                        }
                    });
                }

            } catch (InterruptedException e) {
                // We may have been interrupted because it was time to quit.
                if (mQuit) {
                    return;
                }
                continue;
            }
        }
    }

run方法內(nèi)循環(huán)的過(guò)程中每次從mCacheQueue拿出一個(gè)request請(qǐng)求,對(duì)其添加已經(jīng)訪問(wèn)過(guò)的marker,如果在期間request被取消了,最終會(huì)調(diào)用RequestQueue.finish()方法從mCurrentRequests中remove掉,一次循環(huán)完成;如果request沒(méi)被取消則從緩存中獲取數(shù)據(jù),并且判斷是否為空,如果為空則加入網(wǎng)絡(luò)隊(duì)列中重新請(qǐng)求,一次循環(huán)完成;如果不為空判斷是否過(guò)期,過(guò)期了則加入網(wǎng)絡(luò)隊(duì)列中重新請(qǐng)求,一次循環(huán)完成;如果不過(guò)期判斷是否需要更新緩存,需要?jiǎng)t加入網(wǎng)絡(luò)隊(duì)列中重新請(qǐng)求,否則調(diào)用mDelivery.postResponse()完成數(shù)據(jù)傳遞的過(guò)程,執(zhí)行圖如下:

CacheDispatcher.run.png

NetworkDispatcher也繼承自Thread接口,run方法實(shí)現(xiàn)代碼如下:

@Override
    public void run() {
        Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
        while (true) {
            long startTimeMs = SystemClock.elapsedRealtime();
            Request<?> request;
            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 {
                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");
                    continue;
                }

                addTrafficStatsTag(request);

                //獲取到請(qǐng)求結(jié)果
                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");
                    continue;
                }

                // Parse the response here on the worker thread.
                Response<?> response = request.parseNetworkResponse(networkResponse);
                request.addMarker("network-parse-complete");
                //是否緩存結(jié)果
                if (request.shouldCache() && response.cacheEntry != null) {
                    mCache.put(request.getCacheKey(), response.cacheEntry);
                    request.addMarker("network-cache-written");
                }

                // Post the response back.
                request.markDelivered();
                //交付給mDelivery
                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);
            }
        }
    }

在NetworkDispatcher中主要通過(guò)Network接口performRequest()方法獲得一個(gè)NetworkResponse,進(jìn)而在轉(zhuǎn)換成Delivery.postResponse()可接受的Request對(duì)象進(jìn)行傳遞,其中會(huì)判斷是否需要緩存該request以及相關(guān)error的捕獲并且傳遞給Delivery.postError()。


<h3>ResponseDelivery</h3>

無(wú)論是CacheDispatcher還是NetworkDispatcher,最終的結(jié)果都是交付由ResponseDelivery接口實(shí)現(xiàn)類(lèi)來(lái)進(jìn)行實(shí)現(xiàn):

public interface ResponseDelivery {
    /**
     * Parses a response from the network or cache and delivers it.
     */
    public void postResponse(Request<?> request, Response<?> response);

    /**
     * 處理從緩存和網(wǎng)絡(luò)上獲取的數(shù)據(jù)
     */
    public void postResponse(Request<?> request, Response<?> response, Runnable runnable);

    /**
     *處理錯(cuò)誤的情況
     */
    public void postError(Request<?> request, VolleyError error);
}

其具體實(shí)現(xiàn)類(lèi)為ExecutorDelivery中,其代碼如下:

/**
 * 將請(qǐng)求結(jié)果傳遞給回調(diào)接口
 */
public class ExecutorDelivery implements ResponseDelivery {
    /** Used for posting responses, typically to the main thread. */
    private final Executor mResponsePoster;

    /**
     * 傳入Handler的原因,目的是為了與主線程進(jìn)行交互
     * @param handler {@link Handler} to post responses on
     */
    public ExecutorDelivery(final Handler handler) {
        // Make an Executor that just wraps the handler.
        mResponsePoster = new Executor() {
            @Override
            public void execute(Runnable command) {
                handler.post(command);
            }
        };
    }
    ...
      
    @Override
    public void postResponse(Request<?> request, Response<?> response, Runnable runnable) {
        //request傳遞標(biāo)記
        request.markDelivered();
        request.addMarker("post-response");
        mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, runnable));
    }

    @Override
    public void postError(Request<?> request, VolleyError error) {
        request.addMarker("post-error");
        Response<?> response = Response.error(error);
        mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, null));
    }

    /**
     * A Runnable used for delivering network responses to a listener on the
     * main thread.
     */
    @SuppressWarnings("rawtypes")
    private class ResponseDeliveryRunnable implements Runnable {
        private final Request mRequest;
        private final Response mResponse;
        private final Runnable mRunnable;

        public ResponseDeliveryRunnable(Request request, Response response, Runnable runnable) {
            mRequest = request;
            mResponse = response;
            mRunnable = runnable;
        }

        @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;
            }

            // 傳遞請(qǐng)求的結(jié)果,對(duì)應(yīng)調(diào)用相應(yīng)的回調(diào)接口,看mRequest對(duì)應(yīng)實(shí)現(xiàn)類(lèi)
            //如果是StringRequest,則回調(diào)對(duì)應(yīng)接口。
            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();
            }
       }
    }
}

從Dispatcher那邊獲取到request和response最終傳遞到內(nèi)部類(lèi)ResponseDeliveryRunnable中進(jìn)行處理,如果request是被finish的則丟棄傳遞,否則調(diào)用Request的對(duì)應(yīng)的deliverResponse或者deliverError方法。這里要注意以下,該方法中傳遞了handler變量進(jìn)來(lái),這個(gè)變量是主線程的handler,也就保證了request的回調(diào)從工作線程切換回了主線程,其初始化代碼如下:

public RequestQueue(Cache cache, Network network, int threadPoolSize) {
        this(cache, network, threadPoolSize,
                new ExecutorDelivery(new Handler(Looper.getMainLooper())));
    }

<h4>Request</h4>

Request類(lèi)是一個(gè)抽象方法,其子類(lèi)實(shí)現(xiàn)主要有:StringRequest,JsonRequest,ImageRequest .etc ,為了簡(jiǎn)單查看后續(xù)步驟,我們拿StringRequest來(lái)查看:

 /**
     * Delivers error message to the ErrorListener that the Request was
     * initialized with.
     *
     * @param error Error details
     */
    public void deliverError(VolleyError error) {
        if (mErrorListener != null) {
            mErrorListener.onErrorResponse(error);
        }
    }
  @Override
    protected void deliverResponse(String response) {
        if (mListener != null) {
            mListener.onResponse(response);
        }
    }

到這里就執(zhí)行到了最終的回調(diào),所有的過(guò)程也就完成了。


<h4>個(gè)人總結(jié)</h4>

個(gè)人認(rèn)為volley的精髓在于面向接口編程,具有非常廣闊的拓展性,開(kāi)發(fā)者完全可以自主寫(xiě)一套自己的volley邏輯,充分解耦了各個(gè)模塊,使用組合的方式進(jìn)行編程,是我們學(xué)習(xí)設(shè)計(jì)代碼的一個(gè)非常好的庫(kù)吧。

附上Volley過(guò)程圖:

volley流程圖.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容