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