二、Volley源码解析
2.1 Volley框架结构
根据Volley的框架结构,在上一章可以看出所有的Request请求都是按照这个流程处理,那么我将从请求流程进行源代码分析.
其框架主要分为3部分:
(1)Main Thread中创建Request以及解析显示请求返回结果;
(2)Cache Thread在Cache中处理请求,若请求的内容在缓存中已存在,则从缓存中取出并返回;
(3)NetWork Thread,当请求在缓存中找不到时,则需要从访问网络获取数据.
主线程和Cache线程都只有一个,而NetWork Thread线程可以有很多个(默认是4个),这样能够解决并行问题.
2.2 Volley之RequestQueue
RequestQueue请求队列作为Volley框架使用过程第一个需要创建目标,其内部通过调用Volley类的静态函数进行创建.
<code class="hljs cpp has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> RequestQueue newRequestQueue(Context context, HttpStack <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">stack</span>, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> maxDiskCacheBytes) { File cacheDir = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> File(context.getCacheDir(), DEFAULT_CACHE_DIR) ...<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//省略代码:主要内容</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//1、创建UserAgent用来封装应用的包名跟版本号,提供给服务器</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//2、根据当前系统的版本号来选择HttpStack,若版本大于等于9(Android 2.2以上),使用HttpURLConnection,所以使用一个HurlStack;若小于9,则使用HttpClient.</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//3、创建一个NetWork,调用其构造函数并传入参数stack,去跟网络进行通信.</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//4、创建一个DiskBasedCache对象,和Network一起,传给RequestQueue作为参数,创建RequestQueue对象.</span> RequestQueue <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">queue</span> = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> RequestQueue(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> DiskBasedCache(cacheDir), network);<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//创建RequestQueue</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">queue</span>.start();<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//调用RequestQueue的start方法</span> }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li></ul>
请求队列作为Volley中所有请求的存储器,其内部使用Set集合来存储创建的Request,所有在队列中或者正在被处理的请求都会在这个集合中.
private final Set
<code class="hljs cs has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-title" style="box-sizing: border-box;">RequestQueue</span>(Cache cache, Network network, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> threadPoolSize, ResponseDelivery delivery) { mCache = cache;<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//缓存</span> mNetwork = network;<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//网络</span> mDispatchers = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> NetworkDispatcher[threadPoolSize];<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//网络访问线程池</span> mDelivery = delivery;<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//派送Response的结果给主线程</span> } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-title" style="box-sizing: border-box;">RequestQueue</span>(Cache cache, Network network, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> threadPoolSize) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>(cache, network, threadPoolSize, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> ExecutorDelivery(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Handler(Looper.getMainLooper()))); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-title" style="box-sizing: border-box;">RequestQueue</span>(Cache cache, Network network) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>(cache, network, DEFAULT_NETWORK_THREAD_POOL_SIZE);<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//默认DEFAULT_NETWORK_THREAD_POOL_SIZE=4</span> } </code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li></ul>
其主要工作有:初始化Disk Cache缓存路径、执行网络请求接口NetWork、网络请求调度器NetworkDispatcher和请求结果派送者ResponseDelivery.
在上述创建过程中,无论是CacheDispatcher还是NetworkDispatcher都是继承至Thread.
<code class="hljs java has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">NetworkDispatcher</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">extends</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">Thread</span> {</span> ...<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//省略代码</span> } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">CacheDispatcher</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">extends</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">Thread</span> {</span> ...<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//省略代码</span> }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li></ul>
ResponseDelivery其实是一个接口,其具体实现类似ExecutorDelivery,其构造函数的参数是一个Handler,而Handler的构造函数参数则是Lopper.getMainLooper(),所以这里其实是应用的主线程Looper,也就是说handler其实就是主线的Handler,其作用就是将请求的结果(正确的或者错误的)传输给主线程.
<code class="hljs java has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/** * Delivers responses and errors. */</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">ExecutorDelivery</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">implements</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">ResponseDelivery</span> {</span> <span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/** Used for posting responses, typically to the main thread. */</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> Executor mResponsePoster; <span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/** * Creates a new response delivery interface. *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @param</span> handler {@link Handler} to post responses on */</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-title" style="box-sizing: border-box;">ExecutorDelivery</span>(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> Handler handler) { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Make an Executor that just wraps the handler.</span> mResponsePoster = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Executor() { <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">execute</span>(Runnable command) { handler.post(command); } }; } ...<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//省略代码</span> }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li></ul>
在创建完成RequestQueue对象之后会调用start方法启动所有的dispatcher(CacheDispatcher和NetworkDispatcher):
<code class="hljs java has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"> <span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/** * start方法的作用就是启动所有的dispatcher(CacheDispatcher和NetworkDispatcher) */</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">start</span>() { stop(); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//保证当前所有的正在运行的Dispatcher都停止</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//创建缓存的调度器(也是一个线程),并启动线程</span> mCacheDispatcher = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery); mCacheDispatcher.start(); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//根据线程池的大小,创建相对应的NetworkDispatcher(线程),并启动所有的线程</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> i = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; i < mDispatchers.length; i++) { NetworkDispatcher networkDispatcher = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> NetworkDispatcher(mNetworkQueue, mNetwork, mCache, mDelivery); mDispatchers[i] = networkDispatcher; networkDispatcher.start(); } }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li></ul>
对应start方法当然就有stop方法,用于停止cache and network dispatchers:
<code class="hljs cs has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">stop</span>() { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (mCacheDispatcher != <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) { mCacheDispatcher.quit(); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> i = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; i < mDispatchers.length; i++) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (mDispatchers[i] != <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) { mDispatchers[i].quit(); } } }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li></ul>
在start过程中,出现mCacheQueue, mNetworkQueue,这两个的定义如下:
<code class="hljs java has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//带有优先级cache请求队列</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> PriorityBlockingQueue<Request<?>> mCacheQueue = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> PriorityBlockingQueue<Request<?>>(); <span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/** The queue of requests that are actually going out to the network. */</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> PriorityBlockingQueue<Request<?>> mNetworkQueue = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> PriorityBlockingQueue<Request<?>>();</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li></ul>
可以看到它们其实都是Java并发(Concurrent)包中提供的利用优先级来执行的阻塞队列PriorityBlockingQueue.显然它们就应该是用来放置从外面传进来的请求,比如JsonRequest,ImageRequest和 StringRequest.
在上述分析了怎么启动怎么停止,那么当创建好Request对象时,怎么样才能添加到请求队列中呢?RequestQueue提供了一个add方法,用于将创建好的Request添加到请求队列中.并判断请求的是否存储于缓存中来进行分类.
<code class="hljs java has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <T> Request<T> <span class="hljs-title" style="box-sizing: border-box;">add</span>(Request<T> request) { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 将请求所在队列设置为当前队列,并将请求添加到mCurrentRequests中,表明是正在处理中,并且这里用synchronized来同步</span> request.setRequestQueue(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">synchronized</span> (mCurrentRequests) { mCurrentRequests.add(request); } <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//在这里会设置序列号,保证每个请求都是按顺序被处理的。 </span> request.setSequence(getSequenceNumber()); request.addMarker(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"add-to-queue"</span>); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 如果这个请求是设置不缓存的,那么就会将其添加到mNetworkQueue中,直接去网络中获取数据 </span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (!request.shouldCache()) { mNetworkQueue.add(request); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> request; } <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//到这里,表明这个请求可以去先去缓存中获取数据。 </span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">synchronized</span> (mWaitingRequests) { String cacheKey = request.getCacheKey();<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//key是一个字符串,由Method + ":" + Url组成,默认是Url作为cacheKey</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (mWaitingRequests.containsKey(cacheKey)) {. <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//如果这个请求已经有一个相同的请求(相同的CacheKey)在mWatingRequest中,</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//那么就要将相同CacheKey的请求用一个LinkedList给装起来,先不需要处理,等那个正在处理的请求结束后,再看看应该怎么处理</span> Queue<Request<?>> stagedRequests = mWaitingRequests.get(cacheKey); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (stagedRequests == <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) { stagedRequests = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> LinkedList<Request<?>>(); } stagedRequests.add(request); mWaitingRequests.put(cacheKey, stagedRequests); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (VolleyLog.DEBUG) { VolleyLog.v(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Request for cacheKey=%s is in flight, putting on hold."</span>, cacheKey); } } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//如果mWaitingRequest中没有,那么就将其添加到集合中,将添加到mCacheQueue队列中,表明现在这个cacheKey的请求已经在处理了.</span> mWaitingRequests.put(cacheKey, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>); mCacheQueue.add(request); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> request; } }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li></ul>
当mCacheQueue或者mNetworkQueue利用add方法添加请求之后,在运行的线程就会接收到请求,从而去处理相对应的请求,最后将处理的结果由mDelivery来发送到主线程进行更新.
当请求在缓存线程中或者是在网络线程中处理完成后,每个Request都会去调用对应的finish方法,
<code class="hljs r has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"> void finish(final String tag) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (mRequestQueue != null) { mRequestQueue.finish(this); onFinish(); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">...</span>//省略代码 }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li></ul>
下一步会调用RequestQueue的finish()方法:
<code class="hljs java has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><T> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> finish(Request<T> request) { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//1、从当前队列中移除对应的请求</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">synchronized</span> (mCurrentRequests) { mCurrentRequests.remove(request); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">synchronized</span> (mFinishedListeners) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> (RequestFinishedListener<T> listener : mFinishedListeners) { listener.onRequestFinished(request);<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//请求结束监听</span> } } <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//2-></span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (request.shouldCache()) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">synchronized</span> (mWaitingRequests) { String cacheKey = request.getCacheKey(); Queue<Request<?>> waitingRequests = mWaitingRequests.remove(cacheKey); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (waitingRequests != <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (VolleyLog.DEBUG) { VolleyLog.v(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Releasing %d waiting requests for cacheKey=%s."</span>, waitingRequests.size(), cacheKey); } <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Process all queued up requests. They won't be considered as in flight, but</span> <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// that's not a problem as the cache has been primed by 'request'.</span> mCacheQueue.addAll(waitingRequests); } } } }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li></ul>
第2步中,就是判断这个请求有没有缓存,1)如果有,那么我们这个时候,将前面mWaitingQueue中相同CacheKey的一大批请求再扔到mCacheQueue中,为什么现在才扔呢?因为前面我们不知道相同CacheKey的那个请求到底在缓存中有没有;2)如果没有,它需要去网络中获取,那就等到它从网络中获取之后,放到缓存中后,它结束后且已经缓存了,这个时候,我们就可以保证后面那堆相同CacheKey的请求可以在缓存中去取到数据了,而不需要再去网络中获取了.
最后在RequestQueue中还提供了2个方法用于用户自己随时可控地取消请求:
<code class="hljs java has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//根据顾虑规则进行请求的取消</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">cancelAll</span>(RequestFilter filter) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">synchronized</span> (mCurrentRequests) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> (Request<?> request : mCurrentRequests) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (filter.apply(request)) { request.cancel(); } } } } <span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/** * 根据请求的Tag进行取消 */</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">cancelAll</span>(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> Object tag) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (tag == <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throw</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> IllegalArgumentException(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Cannot cancelAll with a null tag"</span>); } cancelAll(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> RequestFilter() { <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">boolean</span> <span class="hljs-title" style="box-sizing: border-box;">apply</span>(Request<?> request) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> request.getTag() == tag; } }); }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li></ul>
RequestFilter是RequestQueue的内部接口,没有具体实现,上面第二个cancleAll方法的过滤规则就是看Tag是否相等.
到此RequestQueue的源代码核心内容就已经分析完成了.
2.3 Volley之Request
Volley提供的Request有:StringRequest、JsonArrayRequest、JsonObjectRequest、ImageRequest和JsonRequest,其中JsonArrayRequest、JsonObjectRequest继承至JsonRequest,StringRequest、ImageRequest、JsonRequest继承至Request.Volley还可以自定义Request.
Request是一个抽象类.提供了很多的方法,子类需要实现的两个抽象方法为:
<code class="hljs java has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"> <span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/** 子类必须实现这个方法,用于将解析response后的数据传递给request的监听者,解析失败则不会传递. */</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">abstract</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">protected</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">deliverResponse</span>(T response); <span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/** 子类必须实现该方法,用于解析网络请求返回结果response并返回一个恰当的response-type,这个方法将被一个工作线程调用. *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @return</span> The parsed response, or null in the case of an error */</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">abstract</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">protected</span> Response<T> <span class="hljs-title" style="box-sizing: border-box;">parseNetworkResponse</span>(NetworkResponse response);</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li></ul>
具体使用已在前一章讲过,无论是Volley中提供的request还是我们自定义的request,都会通过各自的解析方法解析自定义的数据.
2.4 HttpStack
前面准备了那么多,为了就是进行网络请求,那具体的网络请求是怎么样子的呢?
具体的网络请求实现是在HurlStack/HttpClientStack中实现的,还记得在Volley中创建请求队列时对当前系统版本进行判断,为了就是获取不同网络请求框架:
<code class="hljs lasso has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">stack</span> <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">==</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">null</span>) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (Build<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span>VERSION<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span>SDK_INT <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">>=</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">9</span>) {<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//若版本大于9(Android2.3)则使用HurlStack,其中使用的是HttpURLConnection进行网络请求</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">stack</span> <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">=</span> <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">new</span> HurlStack(); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">若版本小于9(Android2.3)则使用HttpClientStack其中使用的是HttpClient进行网络请求</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">stack</span> <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">=</span> <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">new</span> HttpClientStack(AndroidHttpClient<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span>newInstance(userAgent)); } } <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//再通过NetWork类进行调用具体的网络请求实现类</span> Network network <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">=</span> <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">new</span> BasicNetwork(<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">stack</span>);</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li></ul>
其中NetWork是一个接口,它只包含一个方法: public NetworkResponse performRequest(Request
<code class="hljs r has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">public BasicNetwork(HttpStack httpStack, ByteArrayPool pool) {//<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">...</span>省略代码} //具体网络请求实现调用 @Override public NetworkResponse performRequest(Request<?> request) throws VolleyError { long requestStart = SystemClock.elapsedRealtime(); //<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">...</span>省略代码 // 添加头部信息 Map<String, String> headers = new HashMap<String, String>(); addCacheHeaders(headers, request.getCacheEntry()); httpResponse = mHttpStack.performRequest(request, headers);//调用真正的网络请求类 //各种网络请求返回值判断 //结果返回没有出错的网络请求返回数据 <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> new NetworkResponse(statusCode, responseContents, responseHeaders, false, SystemClock.elapsedRealtime() - requestStart); }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li></ul>
NetworkResponse相当于一个Bean,其作用是将网络请求返回的数据、各种状态码、请求消耗时间等进行封装.
2.5 NetworkDispatcher
网络请求了解了,那管理网络请求的线程呢?其实就是NetworkDispatcher,当用户提交request之后,若CacheDispatcher中没有对应的请求缓存,就必须要进行网络请求,那这时的就需要NetworkDispatcher线程来进行管理了.
<code class="hljs java has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">run</span>() { Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); Request<?> request; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">while</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">true</span>) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">long</span> startTimeMs = SystemClock.elapsedRealtime(); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// release previous request object to avoid leaking request object when mQueue is drained.</span> request = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">try</span> { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 从队列中获取一个请求,若没有则一直阻塞</span> request = mQueue.take(); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">catch</span> (InterruptedException e) { <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// We may have been interrupted because it was time to quit.</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (mQuit) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span>; } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">continue</span>; } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">try</span> { request.addMarker(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"network-queue-take"</span>); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 判断请求有没有取消,如果取消,则不必再继续 </span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (request.isCanceled()) { request.finish(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"network-discard-cancelled"</span>); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">continue</span>; } addTrafficStatsTag(request); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 调用mNetwork去跟网络打交道 </span> NetworkResponse networkResponse = mNetwork.performRequest(request); request.addMarker(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"network-http-complete"</span>); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 如果服务器返回一个未修改(304)的响应,并且这个请求已经发送过响应对象,不需要再继续,因为没改过</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (networkResponse.notModified && request.hasHadResponseDelivered()) { request.finish(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"not-modified"</span>); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">continue</span>; } <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 解析响应的数据,返回Response对象</span> Response<?> response = request.parseNetworkResponse(networkResponse); request.addMarker(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"network-parse-complete"</span>); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 根据request的shouldCache字段来判断是不是需要缓存,如果需要,则将其放到mCache中。 </span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (request.shouldCache() && response.cacheEntry != <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">null</span>) { mCache.put(request.getCacheKey(), response.cacheEntry); request.addMarker(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"network-cache-written"</span>); } <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 调用 mDelivery将Response对象传回主线程进行UI的更新。 </span> request.markDelivered(); mDelivery.postResponse(request, response); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">catch</span> (VolleyError volleyError) { volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs); parseAndDeliverNetworkError(request, volleyError); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">catch</span> (Exception e) { VolleyLog.e(e, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Unhandled exception %s"</span>, e.toString()); VolleyError volleyError = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> VolleyError(e); volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//有错误,也会调用到mDelivery,将错误信息传回到主线程,进行提示 </span> mDelivery.postError(request, volleyError); } } }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li><li style="box-sizing: border-box; padding: 0px 5px;">43</li><li style="box-sizing: border-box; padding: 0px 5px;">44</li><li style="box-sizing: border-box; padding: 0px 5px;">45</li><li style="box-sizing: border-box; padding: 0px 5px;">46</li><li style="box-sizing: border-box; padding: 0px 5px;">47</li><li style="box-sizing: border-box; padding: 0px 5px;">48</li><li style="box-sizing: border-box; padding: 0px 5px;">49</li><li style="box-sizing: border-box; padding: 0px 5px;">50</li><li style="box-sizing: border-box; padding: 0px 5px;">51</li><li style="box-sizing: border-box; padding: 0px 5px;">52</li><li style="box-sizing: border-box; padding: 0px 5px;">53</li><li style="box-sizing: border-box; padding: 0px 5px;">54</li><li style="box-sizing: border-box; padding: 0px 5px;">55</li><li style="box-sizing: border-box; padding: 0px 5px;">56</li><li style="box-sizing: border-box; padding: 0px 5px;">57</li><li style="box-sizing: border-box; padding: 0px 5px;">58</li><li style="box-sizing: border-box; padding: 0px 5px;">59</li><li style="box-sizing: border-box; padding: 0px 5px;">60</li><li style="box-sizing: border-box; padding: 0px 5px;">61</li><li style="box-sizing: border-box; padding: 0px 5px;">62</li><li style="box-sizing: border-box; padding: 0px 5px;">63</li><li style="box-sizing: border-box; padding: 0px 5px;">64</li><li style="box-sizing: border-box; padding: 0px 5px;">65</li></ul>
NetworkDispatcher线程主要完成了:
1) 调用 mQueue的take()方法从队列中获取请求,如果没有请求,则一直阻塞在那里等待,直到队列中有新的请求到来。
2) 判断请求有没有被取消,如果被取消,则重新获取请求。
3) 调用Network对象将请求发送到网络中,并返回一个 NetworkResponse对象。
4) 调用请求的pareseNetworkResonse方法,将NetworkResponse对象解析成相对应的Response对象。
5) 判断请求是否需要缓存,如果需要缓存,则将其Response中cacheEntry对象放到缓存mCache中。
6) 调用 mDelivery将Response对象传到主线程中进行UI更新。
Volley框架中主要的类和流程就如上面所述,其中还有很多小细节没有描述,但是根据Volley使用的流程完全能够看得懂其源代码.
转自:http://blog.csdn.net/lhqj1992/article/details/51878194