溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Android框架之Volley源碼的示例分析

發(fā)布時(shí)間:2021-06-08 14:38:56 來(lái)源:億速云 閱讀:136 作者:小新 欄目:開(kāi)發(fā)技術(shù)

這篇文章主要介紹Android框架之Volley源碼的示例分析,文中介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們一定要看完!

Volley簡(jiǎn)單使用

我這里是以依賴架包的形式 ,大家也可以以gradle的形式進(jìn)行依賴。

Android框架之Volley源碼的示例分析

好了,接下來(lái)上代碼了.....

//獲取volley的請(qǐng)求對(duì)象
        RequestQueue requestQueue = Volley.newRequestQueue(getApplicationContext());
        StringRequest stringRequest = new StringRequest(StringRequest.Method.GET, "http://www.baidu.com", new Response.Listener<String>() {
            @Override
            public void onResponse(String s) {
                Log.d("MainActivity", "----->" + s);

            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError volleyError) {
                Log.d("MainActivity", "---volleyError-->" + volleyError);
            }
        });
        requestQueue.add(stringRequest);

從代碼可以看出,首先newRequestQueue來(lái)獲取到一個(gè)請(qǐng)求隊(duì)列,然后在將StringRequest這個(gè)請(qǐng)求添加到請(qǐng)求隊(duì)列中,就可以了,就是這么簡(jiǎn)單。當(dāng)然請(qǐng)求不值StringRequest,還有JsonObjectRequest ,ImageRequest等等但是用法都是一樣的,這里就不貼代碼了。Volley的簡(jiǎn)單使用就這樣可以進(jìn)行請(qǐng)求了。是不是很簡(jiǎn)單

Volley執(zhí)行原理

但是這個(gè)不是本篇的重點(diǎn),重點(diǎn)是分析一下這些是怎么執(zhí)行的。先上一張圖

Android框架之Volley源碼的示例分析

我們先看看newRequestQueue這個(gè)內(nèi)部是怎么執(zhí)行的,代碼一開(kāi)始連續(xù)執(zhí)行了幾個(gè)重載方法,最后走到newRequestQueue

public static RequestQueue newRequestQueue(Context context, HttpStack stack, int maxDiskCacheBytes) {
    File cacheDir = new File(context.getCacheDir(), "volley");
    String userAgent = "volley/0";

    try {
        String packageName = context.getPackageName();
        PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0);
        userAgent = packageName + "/" + info.versionCode;
    } catch (NameNotFoundException var7) {
        ;
    }

    //這里進(jìn)行了一個(gè)版本的判斷 2.3之前用的是HTTPClient,2.3之后使用的是HttpURLConnection
    if (stack == null) {
        if (VERSION.SDK_INT >= 9) {
            stack = new HurlStack();
        } else {
            stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));
        }
    }

    Network network = new BasicNetwork((HttpStack)stack);
    RequestQueue queue;
    if (maxDiskCacheBytes <= -1) {
        queue = new RequestQueue(new DiskBasedCache(cacheDir), network);
    } else {
        queue = new RequestQueue(new DiskBasedCache(cacheDir, maxDiskCacheBytes), network);
    }

    queue.start();
    return queue;
}

在這里,我們看到了一個(gè)版本判斷,是不是瞬間感覺(jué)有點(diǎn)熟悉,沒(méi)錯(cuò),我們前面說(shuō)的,volley2.3之前用的是HTTPClient,2.3之后使用的是HttpURLConnection就是在這里進(jìn)行判斷的。接著看queue.start();

public void start() {
        this.stop();
        this.mCacheDispatcher = new CacheDispatcher(this.mCacheQueue, this.mNetworkQueue, this.mCache, this.mDelivery);
        this.mCacheDispatcher.start();

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

    }

mCacheDispatcher是緩存調(diào)度線程,NetworkDispatcher是網(wǎng)絡(luò)調(diào)度線程,而這個(gè)this.mDispatchers.length系統(tǒng)默認(rèn)的大小為4,也就是說(shuō),在這里總共啟動(dòng)了5個(gè)線程在后臺(tái)運(yùn)行。

好了,到這里,就可以了,看源碼不要每一行都弄懂,不然,出不來(lái)了。到這里就拿到了這個(gè)RequestQueue對(duì)象?;剡^(guò)頭來(lái)看前面使用的代碼

//獲取volley的請(qǐng)求對(duì)象
RequestQueue requestQueue = Volley.newRequestQueue(getApplicationContext());
StringRequest stringRequest = new StringRequest(StringRequest.Method.GET, "http://www.baidu.com", new Response.Listener<String>() {
    @Override
    public void onResponse(String s) {
        Log.d("MainActivity", "----->" + s);

    }
}, new Response.ErrorListener() {
    @Override
    public void onErrorResponse(VolleyError volleyError) {
        Log.d("MainActivity", "---volleyError-->" + volleyError);
    }
});
requestQueue.add(stringRequest);

我們拿到這個(gè)RequestQueue對(duì)象以后,然后就把這個(gè)請(qǐng)求通過(guò)add方法添加到隊(duì)列中,我們看看這個(gè)add()方法是怎么執(zhí)行的。

public <T> Request<T> add(Request<T> request) {
        request.setRequestQueue(this);
        Set var2 = this.mCurrentRequests;
        synchronized(this.mCurrentRequests) {
            this.mCurrentRequests.add(request);
        }

        request.setSequence(this.getSequenceNumber());
        request.addMarker("add-to-queue");
        if (!request.shouldCache()) { //如果不能緩存
            this.mNetworkQueue.add(request);
            return request;
        } else {
            Map var7 = this.mWaitingRequests;
            synchronized(this.mWaitingRequests) {
                String cacheKey = request.getCacheKey();
                if (this.mWaitingRequests.containsKey(cacheKey)) { //判斷之前是否執(zhí)行過(guò),但是還沒(méi)有返回結(jié)果
                    Queue<Request<?>> stagedRequests = (Queue)this.mWaitingRequests.get(cacheKey);
                    if (stagedRequests == null) {
                        stagedRequests = new LinkedList();
                    }

                    ((Queue)stagedRequests).add(request);
                    this.mWaitingRequests.put(cacheKey, stagedRequests);
                    if (VolleyLog.DEBUG) {
                        VolleyLog.v("Request for cacheKey=%s is in flight, putting on hold.", new Object[]{cacheKey});
                    }
                } else {
                //沒(méi)有的話就將請(qǐng)求加入緩存隊(duì)列mCacheQueue,同時(shí)加入mWaitingRequests中用來(lái)做下次同樣請(qǐng)求來(lái)時(shí)的重復(fù)判斷依據(jù)
                    this.mWaitingRequests.put(cacheKey, (Object)null);
                    this.mCacheQueue.add(request);
                }

                return request;
            }
        }
    }

從代碼中可以看出,首先判斷是否可以緩存,當(dāng)然,默認(rèn)是可以緩存的。如果不能緩存的話,則通過(guò)this.mNetworkQueue.add(request);將請(qǐng)求添加到網(wǎng)絡(luò)請(qǐng)求隊(duì)列中。如果可以緩存,則還會(huì)判斷一次這個(gè)請(qǐng)求是否請(qǐng)求,如果執(zhí)行過(guò)就就通過(guò)this.mWaitingRequests.put(cacheKey, stagedRequests);添加到mWaitingRequests隊(duì)列,不在重復(fù)請(qǐng)求。否則就加入到緩存隊(duì)列。

大體的流程是這樣?,F(xiàn)在我們看看緩存的,和網(wǎng)絡(luò)的是怎么執(zhí)行的。我們找到start()方法

public void start() {
        this.stop();
        this.mCacheDispatcher = new CacheDispatcher(this.mCacheQueue, this.mNetworkQueue, this.mCache, this.mDelivery);
        this.mCacheDispatcher.start();

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

    }

先看CacheDispatcher,找到run()方法

public void run() {
        if (DEBUG) {
            VolleyLog.v("start new dispatcher", new Object[0]);
        }

        Process.setThreadPriority(10);
        this.mCache.initialize();

        while(true) {
            while(true) {
                while(true) {
                    while(true) {
                        try {
                            while(true) {
                                final Request<?> request = (Request)this.mCacheQueue.take(); //從緩存隊(duì)列中獲取到一個(gè)請(qǐng)求
                                request.addMarker("cache-queue-take");
                                if (request.isCanceled()) { //判斷請(qǐng)求是否取消,如果取消了,那就將該請(qǐng)求finish掉
                                    request.finish("cache-discard-canceled");
                                } else {
                                    Entry entry = this.mCache.get(request.getCacheKey());
                                    if (entry == null) {//如果從緩存中取出來(lái)的內(nèi)容為空,則將請(qǐng)求加入到網(wǎng)絡(luò)線程中再次請(qǐng)求
                                        request.addMarker("cache-miss");
                                        this.mNetworkQueue.put(request);
                                    } else if (entry.isExpired()) { //如果請(qǐng)求過(guò)期了,則將請(qǐng)求加入到網(wǎng)絡(luò)線程中再次請(qǐng)求
                                        request.addMarker("cache-hit-expired");
                                        request.setCacheEntry(entry);
                                        this.mNetworkQueue.put(request);
                                    } else { //將數(shù)據(jù)回調(diào)到主線程
                                        request.addMarker("cache-hit");
                                        Response<?> response = request.parseNetworkResponse(new NetworkResponse(entry.data, entry.responseHeaders));
                                        request.addMarker("cache-hit-parsed");
                                        if (entry.refreshNeeded()) {
                                            request.addMarker("cache-hit-refresh-needed");
                                            request.setCacheEntry(entry);
                                            response.intermediate = true;
                                            this.mDelivery.postResponse(request, response, new Runnable() {
                                                public void run() {
                                                    try {
                                                        CacheDispatcher.this.mNetworkQueue.put(request);
                                                    } catch (InterruptedException var2) {
                                                        ;
                                                    }

                                                }
                                            });
                                        } else {
                                            this.mDelivery.postResponse(request, response);
                                        }
                                    }
                                }
                            }
                        } catch (InterruptedException var4) {
                            if (this.mQuit) {
                                return;
                            }
                        }
                    }
                }
            }
        }
    }

這里嵌套了幾個(gè)循環(huán),有點(diǎn)凌亂啊,但是慢慢分析的話,就會(huì)發(fā)現(xiàn),其實(shí)很清晰。我在注釋上面寫(xiě)了,這里就不重復(fù)了

我們?cè)诳纯碞etworkDispatcher,看看網(wǎng)絡(luò)線程是怎么執(zhí)行的。一樣找到run()方法

public void run() {
        Process.setThreadPriority(10);

        while(true) {
            long startTimeMs;
            Request request;
            while(true) {
                startTimeMs = SystemClock.elapsedRealtime();

                try {
                    request = (Request)this.mQueue.take(); //獲取到一個(gè)請(qǐng)求
                    break;
                } catch (InterruptedException var6) {
                    if (this.mQuit) {
                        return;
                    }
                }
            }

            try {
                request.addMarker("network-queue-take");
                if (request.isCanceled()) { //如果請(qǐng)求取消了,則將請(qǐng)求finish掉
                    request.finish("network-discard-cancelled");
                } else {//進(jìn)行網(wǎng)絡(luò)請(qǐng)求
                    this.addTrafficStatsTag(request);
                    NetworkResponse networkResponse = this.mNetwork.performRequest(request);
                    request.addMarker("network-http-complete");
                    if (networkResponse.notModified && request.hasHadResponseDelivered()) {
                        request.finish("not-modified");
                    } else {
                        Response<?> response = request.parseNetworkResponse(networkResponse);
                        request.addMarker("network-parse-complete");
                        if (request.shouldCache() && response.cacheEntry != null) {
                            this.mCache.put(request.getCacheKey(), response.cacheEntry);
                            request.addMarker("network-cache-written");
                        }

                        request.markDelivered();
                        this.mDelivery.postResponse(request, response);
                    }
                }
            } catch (VolleyError var7) {
                var7.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs);
                this.parseAndDeliverNetworkError(request, var7);
            } catch (Exception var8) {
                VolleyLog.e(var8, "Unhandled exception %s", new Object[]{var8.toString()});
                VolleyError volleyError = new VolleyError(var8);
                volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs);
                this.mDelivery.postError(request, volleyError);
            }
        }
    }

代碼比較多,我們直接找到NetworkResponse networkResponse = this.mNetwork.performRequest(request);這句代碼,這句代碼就是請(qǐng)求網(wǎng)絡(luò)的代碼,最核心的。performRequest是一個(gè)接口,我們看看這個(gè)performRequest()方法。Network在最開(kāi)始說(shuō)版本判斷的時(shí)候里面有一句代碼Network network = new BasicNetwork((HttpStack)stack);  從這句代碼,我們可以知道BasicNetwork才是最終實(shí)現(xiàn)網(wǎng)絡(luò)請(qǐng)求的類,我們找到performRequest方法

public NetworkResponse performRequest(Request<?> request) throws VolleyError {
        long requestStart = SystemClock.elapsedRealtime();

        while(true) {
            HttpResponse httpResponse = null;
            byte[] responseContents = null;
            Map responseHeaders = Collections.emptyMap();

            try {
                Map<String, String> headers = new HashMap();
                this.addCacheHeaders(headers, request.getCacheEntry());
                httpResponse = this.mHttpStack.performRequest(request, headers);
                StatusLine statusLine = httpResponse.getStatusLine();
                int statusCode = statusLine.getStatusCode();
                responseHeaders = convertHeaders(httpResponse.getAllHeaders());
                if (statusCode == 304) {
                    Entry entry = request.getCacheEntry();
                    if (entry == null) {
                        return new NetworkResponse(304, (byte[])null, responseHeaders, true, SystemClock.elapsedRealtime() - requestStart);
                    }

                    entry.responseHeaders.putAll(responseHeaders);
                    return new NetworkResponse(304, entry.data, entry.responseHeaders, true, SystemClock.elapsedRealtime() - requestStart);
                }

                if (statusCode == 301 || statusCode == 302) {
                    String newUrl = (String)responseHeaders.get("Location");
                    request.setRedirectUrl(newUrl);
                }

                byte[] responseContents;
                if (httpResponse.getEntity() != null) {
                    responseContents = this.entityToBytes(httpResponse.getEntity());
                } else {
                    responseContents = new byte[0];
                }

                long requestLifetime = SystemClock.elapsedRealtime() - requestStart;
                this.logSlowRequests(requestLifetime, request, responseContents, statusLine);
                if (statusCode >= 200 && statusCode <= 299) {
                    return new NetworkResponse(statusCode, responseContents, responseHeaders, false, SystemClock.elapsedRealtime() - requestStart);
                }

                throw new IOException();
            } catch (SocketTimeoutException var12) {
                attemptRetryOnException("socket", request, new TimeoutError());
            } catch (ConnectTimeoutException var13) {
                attemptRetryOnException("connection", request, new TimeoutError());
            } catch (MalformedURLException var14) {
                throw new RuntimeException("Bad URL " + request.getUrl(), var14);
            } catch (IOException var15) {
                int statusCode = false;
                NetworkResponse networkResponse = null;
                if (httpResponse == null) {
                    throw new NoConnectionError(var15);
                }

                int statusCode = httpResponse.getStatusLine().getStatusCode();
                if (statusCode != 301 && statusCode != 302) {
                    VolleyLog.e("Unexpected response code %d for %s", new Object[]{statusCode, request.getUrl()});
                } else {
                    VolleyLog.e("Request at %s has been redirected to %s", new Object[]{request.getOriginUrl(), request.getUrl()});
                }

                if (responseContents == null) {
                    throw new NetworkError(networkResponse);
                }

                networkResponse = new NetworkResponse(statusCode, (byte[])responseContents, responseHeaders, false, SystemClock.elapsedRealtime() - requestStart);
                if (statusCode != 401 && statusCode != 403) {
                    if (statusCode != 301 && statusCode != 302) {
                        throw new ServerError(networkResponse);
                    }

                    attemptRetryOnException("redirect", request, new AuthFailureError(networkResponse));
                } else {
                    attemptRetryOnException("auth", request, new AuthFailureError(networkResponse));
                }
            }
        }
    }

代碼比較多,但是大多數(shù)代碼是判斷狀態(tài)返回碼的,不需要理會(huì)。

我們直接看httpResponse = this.mHttpStack.performRequest(request, headers);這一句代碼,HttpStack這個(gè)有沒(méi)有很熟悉。沒(méi)有??沒(méi)關(guān)系我在復(fù)制一次代碼

if (stack == null) {
    if (VERSION.SDK_INT >= 9) {
        stack = new HurlStack();
    } else {
        stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));
    }
}

以上是“Android框架之Volley源碼的示例分析”這篇文章的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對(duì)大家有幫助,更多相關(guān)知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI