淺談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);做的事情