浅谈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);做的事情