淺談Volley請求
- 2019 年 12 月 5 日
- 筆記

淺談Volley請求Queue = Volley.newRequestQueue(context)深入理解RequestQueue request
先簡單介紹一下Volley的誕生背景 Volley誕生於 2013年 Google I/O大會上 是Google開發工程師寫的一個網路請求框架 特點是進行數據量不大,但通訊頻繁的網路操作,內部還封裝了圖片載入的控制項 NetworkImageView 用於直接在網路上面載入圖片 本文只是對
RequestQueue requestQueue = Volley.newRequestQueue(context);
這一行程式碼的深入理解 別小看這一行程式碼 這一行程式碼資訊量很大的 廢話不多說 我們就直接來閱讀源碼吧(Read The Fucking Source Code)
當我們用Volley執行網路請求時 首先就會寫這一行程式碼
RequestQueue queue = Volley.newRequestQueue(context);
點進去之後 程式碼如下(class volley)
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // package com.android.volley.toolbox; import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager.NameNotFoundException; import android.net.http.AndroidHttpClient; import android.os.Build.VERSION; import com.android.volley.Network; import com.android.volley.RequestQueue; import java.io.File; public class Volley { private static final String DEFAULT_CACHE_DIR = "volley"; public Volley() { } public static RequestQueue newRequestQueue(Context context, HttpStack stack) { 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 var6) { } 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 = new RequestQueue(new DiskBasedCache(cacheDir), network); queue.start(); return queue; } public static RequestQueue newRequestQueue(Context context) { return newRequestQueue(context, (HttpStack)null); } }
這個類裡面主要是看幾行程式碼
我們調用的是一個參數的構造方法 但是他還是會去掉兩個參數的構造方法 兩個參數的構造方法 看下面這一行程式碼
RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir), network);
這裡new了一個RequestQueue 的對象
這一行程式碼第一個參數告訴我們的資訊是
1.new DiskBasedCache(cacheDir) 字面的意思是基於磁碟的快取 裡面的參數我們可以在volley類里看到 如下:
private static final String DEFAULT_CACHE_DIR = "volley"; File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR);
這兩行程式碼的意思是在項目data/data包下創建一個volley的文件夾
然後再看一下DiskBasedCache類的實現的一些細節 點開之後我們發現DiskBasedCache類裡面的程式碼行數五百多行 我們還是挑重點看
public DiskBasedCache(File rootDirectory, int maxCacheSizeInBytes) { this.mEntries = new LinkedHashMap(16, 0.75F, true); this.mTotalSize = 0L; this.mRootDirectory = rootDirectory; this.mMaxCacheSizeInBytes = maxCacheSizeInBytes; } private static final int DEFAULT_DISK_USAGE_BYTES = 5242880; public DiskBasedCache(File rootDirectory) { this(rootDirectory, 5242880); }
點開他的構造方法可以看到是給成員變數賦值 我們重點看參數二 參數二我們可以明顯看到了一個數 那就是規定默認磁碟快取的大小時5M
所以我們在創建一個請求隊列時 第一個參數得到的結論是
1.volley文件夾是在這裡創建的,
2. 磁碟快取的大小時5M,看到這裡我們大致了解了一些基本資訊
我們接著往下看 創建請求隊列時的第二個參數是什麼意思 :
network 點進去之後
public interface Network { NetworkResponse performRequest(Request<?> var1) throws VolleyError; }
這就是一個介面 通過注釋了解到 主要是由他來執行網路請求的 那麼他是怎樣執行網路請求的呢 我們接著往下看
點到BasicNetwork類裡面看到 (由於源碼比較多 我們就看這一行程式碼)
httpResponse = this.mHttpStack.performRequest(request, headers);
是通過這一行來執行網路請求的
回過頭來 我們再來看volley類程式碼
Network network = new BasicNetwork(stack);
這一行程式碼參數的好像在哪裡見過 沒錯就是默認給我們傳過來的值就是null 這行程式碼的上面 有一個判斷
if (stack == null) { if (VERSION.SDK_INT >= 9) { stack = new HurlStack(); } else { stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent)); } }
這裡給stack賦值了 如果版本大於9 的話 stack = new HurlStack();點到HurlStack類裡面看到
protected HttpURLConnection createConnection(URL url) throws IOException { return (HttpURLConnection)url.openConnection(); }
這個方法我們可以看到底層是通過HttpURLConnecttion來完成網路請求的
如果版本小於9 的話用的是HttpClient來執行網路請求的
總結:從創建一個請求隊列我們可以看到以下幾點:
1.volley文件夾是在這裡創建的,
2. 磁碟快取的大小時5M,
3.底層執行網路請求所用的框架 說了半天現在也是在說RequestQueue後面的兩個參數的意思 我們接著往下看RequestQuene的源碼
RequestQuene 類裡面也就三百多行程式碼 這裡我們就看跳過來的程式碼
private static final int DEFAULT_NETWORK_THREAD_POOL_SIZE = 4; public RequestQueue(Cache cache, Network network) { this(cache, network, 4); } public RequestQueue(Cache cache, Network network, int threadPoolSize, ResponseDelivery delivery) { this.mSequenceGenerator = new AtomicInteger(); this.mWaitingRequests = new HashMap(); this.mCurrentRequests = new HashSet(); this.mCacheQueue = new PriorityBlockingQueue(); this.mNetworkQueue = new PriorityBlockingQueue(); this.mCache = cache; this.mNetwork = network; this.mDispatchers = new NetworkDispatcher[threadPoolSize]; this.mDelivery = delivery; } public RequestQueue(Cache cache, Network network, int threadPoolSize) { this(cache, network, threadPoolSize, new ExecutorDelivery(new Handler(Looper.getMainLooper()))); }
進去之後看到了一個常量
DEFAULT_NETWORK_THREAD_POOL_SIZE
這裡我們可以看到 默認的網路執行緒池的大小為四
這裡的執行緒池可以優化 這裡可以看到volley里的執行緒池是由數組組成 並且默認的執行緒數為四個
還可以看到第四個參數
new ExecutorDelivery(new Handler(Looper.getMainLooper())))
這裡使用hander綁定一個主執行緒的looper 來完成執行緒的之間的切換的
總結:
RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir), network);
我們寫的這一行程式碼 volley幫我們做了
mCache = cache;//磁碟快取 mNectwork = network;//網路請求的處理 mDispatchers = new NetworkDispatcher[threadPoolSize]; //執行緒池 mDelivery = delivery;//初始化分發器 做網路結果和錯誤的回溯
我們接著往下看 看volley源碼知道 現在該啟動這個隊列了
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(); } }
這裡是先開啟了一個快取的分發器
mCacheQueue, mNetworkQueue, mCache, mDelivery
有四個參數 第三個和第四個參數是在創建隊列的時候調用
第一和第二個參數是在RequestQueue類裡面已經初始化好了 這兩個隊列的意思是首先看快取隊列裡面有沒有請求 有的話就直接用 沒有的話 就放在網路隊列里
點到CacheDispatcher裡面可以看到這是一個執行緒 他的run方法是一個死循環
再來看start方法 裡面有一個for循環 mDispatchers.length的值 我們已經知道是四了 意思是創建四個網路分發器
所以我們start方法里一次性啟動了五條執行緒
以上這些內容就是我們在創建一個請求隊列時volley幫我們做的所有事情 也就是開篇講的mRequestQueue = Volley.newRequestQueue(context);做的事情