Android:Volley解析(一)之GET、POST请求篇

一、 Volley 的地位

自2013年Google I/O 大会上,Google 推出 Volley 之后,一直到至今,由于其使用简单、代码轻量、通信速度快、并发量大等特点,倍受开发者们的青睐。 
先看两张图,让图片告诉我们 Volley 的用处; 
第一张 Volley 的经典图 
这里写图片描述 
通过上图,我们可以发现 Volley适合网络通信频繁操作,并能同时实现多个网络通信。 
第二张图 
这里写图片描述
我们在以前在 ListView 的 item 中如果有网络请求,一般都是通过Task 异步任务来完成,并在完成之后通知 Adapter 更新数据。而Volley 不需要这么麻烦,因为里面已经为我们封装好了处理的线程,网络请求,缓存的获取,数据的回掉都是对应不同的线程。

二、Volley使用步骤及基本分析

volley 的使用遵循以下四步: 
1、获取请求队里RequestQueue 
RequestQueue mRequestQueue = Vollay.newRequestQueue(Context context) ; 
2、启动请求队列 
mRequestQueue.start(); 
以上这两步通常也归为一步 
3、获取请求Request 
Request mRequest = new ObjectRequest(…) ; 
ObjectRequest需要根据自己请求返回的数据来定制,继承之抽象类Request,Vollay 已经为我们实现了 StringRequest、JsonArrayRequest、JsonObjectRequest、ImageRequest请求; 
4、把请求添加到请求队列中 
mRequestQueue.add(mRequest); 
说明:在一个项目中,请求队列不需要出现多个,一般整个项目中共用同一个mRequestQueue,因为请求队列启动的时候会做以下事情

<code class=" hljs java" style="box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; padding: 0.5em; color: rgb(0, 0, 0); border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; display: block; background-image: initial; background-attachment: initial; background-color: transparent !important; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;">    <span class="hljs-javadoc" style="box-sizing: border-box; color: rgb(136, 136, 255);">/**
     * Starts the dispatchers in this queue.
     */</span>
    <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">public</span> <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">void</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(136, 0, 0); font-weight: bold;">start</span>() {
    <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">//结束队列中所有的线程</span>
        stop();  <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">// Make sure any currently running dispatchers are stopped.</span>
        <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">// Create the cache dispatcher and start it.</span>
        <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">//初始化缓存处理线程</span>
        mCacheDispatcher = <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">new</span> CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery);
        <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">//启动缓存线程</span>
        mCacheDispatcher.start();

        <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">// Create network dispatchers (and corresponding threads) up to the pool size.</span>
        <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">//启动网络请求处理线程,默认为5个,可以自己设定 size</span>
        <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">for</span> (<span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">int</span> i = <span class="hljs-number" style="box-sizing: border-box; color: rgb(0, 136, 0);">0</span>; i < mDispatchers.length; i++) {
            NetworkDispatcher networkDispatcher = <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">new</span> NetworkDispatcher(mNetworkQueue, mNetwork,
                    mCache, mDelivery);
            <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">//保存网络请求线程</span>
            mDispatchers[i] = networkDispatcher;
            <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">//启动网络请求处理线程</span>
            networkDispatcher.start();
        }
    }</code>

启动一个缓存mCacheDispatcher线程,用来读取缓存数据,启动若干个网络请求mDispatchers线程,用来实现网络通信。 
mCacheDispatcher线程的 run 方法

<code class=" hljs java" style="box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; padding: 0.5em; color: rgb(0, 0, 0); border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; display: block; background-image: initial; background-attachment: initial; background-color: transparent !important; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;">    <span class="hljs-annotation" style="box-sizing: border-box; color: rgb(136, 136, 136);">@Override</span>
    <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">public</span> <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">void</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(136, 0, 0); font-weight: bold;">run</span>() {
        <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">if</span> (DEBUG) VolleyLog.v(<span class="hljs-string" style="box-sizing: border-box; color: rgb(136, 0, 0);">"start new dispatcher"</span>);
        Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);

        <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">// Make a blocking call to initialize the cache.</span>
        <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">//初始化缓存</span>
        mCache.initialize();
        <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">//循环获取缓存请求</span>
        <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">while</span> (<span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">true</span>) {
            <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">try</span> {
                <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">// Get a request from the cache triage queue, blocking until</span>
                <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">// at least one is available.</span>
                <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">//从缓存队列中获取缓存请求,如果没有缓存请求,这个方法会阻塞在这里</span>
                <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">final</span> Request request = mCacheQueue.take();
                <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">//打印 log 信息</span>
                request.addMarker(<span class="hljs-string" style="box-sizing: border-box; color: rgb(136, 0, 0);">"cache-queue-take"</span>);

                <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">// If the request has been canceled, don't bother dispatching it.</span>
                <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">//如果请求终止了,结束本次循环</span>
                <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">if</span> (request.isCanceled()) {
                    request.finish(<span class="hljs-string" style="box-sizing: border-box; color: rgb(136, 0, 0);">"cache-discard-canceled"</span>);
                    <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">continue</span>;
                }

                <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">// Attempt to retrieve this item from cache.</span>
               <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">//获取缓存数据,如果没有,把请求加入到网络请求的队列中</span>
                Cache.Entry entry = mCache.get(request.getCacheKey());
                <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">if</span> (entry == <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">null</span>) {
                    request.addMarker(<span class="hljs-string" style="box-sizing: border-box; color: rgb(136, 0, 0);">"cache-miss"</span>);
                    Log.i(<span class="hljs-string" style="box-sizing: border-box; color: rgb(136, 0, 0);">"CacheDispatcher"</span>, <span class="hljs-string" style="box-sizing: border-box; color: rgb(136, 0, 0);">"没有缓存数据:"</span> + request.getUrl());
                    mNetworkQueue.put(request);
                    <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">continue</span>;
                }

                <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">// If it is completely expired, just send it to the network.</span>
                <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">//判断缓存是否已经过期,如果过期,把请求加入到网络请求的队列中,直接请求网络获取数据</span>
                <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">if</span> (entry.isExpired()) {
                    request.addMarker(<span class="hljs-string" style="box-sizing: border-box; color: rgb(136, 0, 0);">"cache-hit-expired"</span>);
                    request.setCacheEntry(entry);
                    Log.i(<span class="hljs-string" style="box-sizing: border-box; color: rgb(136, 0, 0);">"CacheDispatcher"</span>, <span class="hljs-string" style="box-sizing: border-box; color: rgb(136, 0, 0);">"缓存数据过期:"</span> + request.getUrl());
                    mNetworkQueue.put(request);
                    <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">continue</span>;
                }

                <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">// We have a cache hit; parse its data for delivery back to the request.</span>
                <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">// 已经获取到了有效的缓存数据,回调给 request 的parseNetworkResponse,需要自己根据需求来解析数据</span>
                request.addMarker(<span class="hljs-string" style="box-sizing: border-box; color: rgb(136, 0, 0);">"cache-hit"</span>);
                Response<?> response = request.parseNetworkResponse(
                        <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">new</span> NetworkResponse(entry.data, entry.responseHeaders));
                request.addMarker(<span class="hljs-string" style="box-sizing: border-box; color: rgb(136, 0, 0);">"cache-hit-parsed"</span>);
                <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">//判断缓存是否需要刷新</span>
                <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">if</span> (!entry.refreshNeeded()) {
                    <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">// Completely unexpired cache hit. Just deliver the response.</span>
                    Log.i(<span class="hljs-string" style="box-sizing: border-box; color: rgb(136, 0, 0);">"CacheDispatcher"</span>, <span class="hljs-string" style="box-sizing: border-box; color: rgb(136, 0, 0);">"获取缓存数据:"</span> + request.getUrl());
                    mDelivery.postResponse(request, response);
                } <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">else</span> {
                    <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">// Soft-expired cache hit. We can deliver the cached response,</span>
                    <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">// but we need to also send the request to the network for</span>
                    <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">// refreshing.</span>
                    request.addMarker(<span class="hljs-string" style="box-sizing: border-box; color: rgb(136, 0, 0);">"cache-hit-refresh-needed"</span>);
                    request.setCacheEntry(entry);

                    <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">// Mark the response as intermediate.</span>
                    response.intermediate = <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">true</span>;

                    <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">// Post the intermediate response back to the user and have</span>
                    <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">// the delivery then forward the request along to the network.</span>
                    mDelivery.postResponse(request, response, <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">new</span> Runnable() {
                        <span class="hljs-annotation" style="box-sizing: border-box; color: rgb(136, 136, 136);">@Override</span>
                        <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">public</span> <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">void</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(136, 0, 0); font-weight: bold;">run</span>() {
                            <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">try</span> {
                                mNetworkQueue.put(request);
                            } <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">catch</span> (InterruptedException e) {
                                <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">// Not much we can do about this.</span>
                            }
                        }
                    });
                }

            } <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">catch</span> (InterruptedException e) {
                <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">// We may have been interrupted because it was time to quit.</span>
                <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">if</span> (mQuit) {
                    <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">return</span>;
                }
                <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">continue</span>;
            }
        }
    }</code>

mDispatchers线程的 run 方法

<code class=" hljs java" style="box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; padding: 0.5em; color: rgb(0, 0, 0); border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; display: block; background-image: initial; background-attachment: initial; background-color: transparent !important; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;">    <span class="hljs-annotation" style="box-sizing: border-box; color: rgb(136, 136, 136);">@Override</span>
    <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">public</span> <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">void</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(136, 0, 0); font-weight: bold;">run</span>() {
        Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
        Request request;
        <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">while</span> (<span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">true</span>) {
            <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">try</span> {
                <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">// Take a request from the queue.</span>
                <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">//获取网络请求,当队列中为空的时候,阻塞</span>
                request = mQueue.take();
            } <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">catch</span> (InterruptedException e) {
                <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">// We may have been interrupted because it was time to quit.</span>
                <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">if</span> (mQuit) {
                    <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">return</span>;
                }
                <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">continue</span>;
            }

            <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">try</span> {
                request.addMarker(<span class="hljs-string" style="box-sizing: border-box; color: rgb(136, 0, 0);">"network-queue-take"</span>);

                <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">// If the request was cancelled already, do not perform the</span>
                <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">// network request.</span>
                <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">if</span> (request.isCanceled()) {
                    request.finish(<span class="hljs-string" style="box-sizing: border-box; color: rgb(136, 0, 0);">"network-discard-cancelled"</span>);
                    <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">continue</span>;
                }

                <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">// Tag the request (if API >= 14)</span>
                <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">if</span> (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
                    TrafficStats.setThreadStatsTag(request.getTrafficStatsTag());
                }

                <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">// Perform the network request.</span>
                <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">//网络请求的基本操作(核心操作),从网络中获取数据</span>
                NetworkResponse networkResponse = mNetwork.performRequest(request);
                request.addMarker(<span class="hljs-string" style="box-sizing: border-box; color: rgb(136, 0, 0);">"network-http-complete"</span>);

                <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">// If the server returned 304 AND we delivered a response already,</span>
                <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">// we're done -- don't deliver a second identical response.</span>
                <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">if</span> (networkResponse.notModified && request.hasHadResponseDelivered()) {
                    request.finish(<span class="hljs-string" style="box-sizing: border-box; color: rgb(136, 0, 0);">"not-modified"</span>);
                    <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">continue</span>;
                }

                <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">// Parse the response here on the worker thread.</span>
                Response<?> response = request.parseNetworkResponse(networkResponse);
                request.addMarker(<span class="hljs-string" style="box-sizing: border-box; color: rgb(136, 0, 0);">"network-parse-complete"</span>);

                <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">// Write to cache if applicable.</span>
                <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">// TODO: Only update cache metadata instead of entire record for 304s.</span>
                <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">//判断是否需要缓存,如果需要则缓存。</span>
                <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">if</span> (request.shouldCache() && response.cacheEntry != <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">null</span>) {
                    mCache.put(request.getCacheKey(), response.cacheEntry);
                    request.addMarker(<span class="hljs-string" style="box-sizing: border-box; color: rgb(136, 0, 0);">"network-cache-written"</span>);
                }

                <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">// Post the response back.</span>
                request.markDelivered();
                mDelivery.postResponse(request, response);
            } <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">catch</span> (VolleyError volleyError) {
                parseAndDeliverNetworkError(request, volleyError);
            } <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">catch</span> (Exception e) {
                VolleyLog.e(e, <span class="hljs-string" style="box-sizing: border-box; color: rgb(136, 0, 0);">"Unhandled exception %s"</span>, e.toString());
                mDelivery.postError(request, <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">new</span> VolleyError(e));
            }
        }
    }</code>

这两个线程处理类型基本相同,都是采用循环的方法,在队列中获取请求,有请求则执行相应的请求,没有则阻塞在下面两行代码中

<code class=" hljs oxygene" style="box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; padding: 0.5em; color: rgb(0, 0, 0); border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; display: block; background-image: initial; background-attachment: initial; background-color: transparent !important; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;"><span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">//阻塞线程的执行</span>
<span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">//缓存线程阻塞的地方</span>
<span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">final</span> Request request = mCacheQueue.<span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">take</span>();
<span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">//网络请求阻塞的地方</span>
request = mQueue.<span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">take</span>();</code>

所以我们一般只需要根据不同的接口,实例化不同的请求 Request,往队列中添加 即可,它首先判断请求是否需要缓存,如果不需要,直接添加到网络请求的队列中,结束下面的操作,如果需要缓存,则把请求添加到缓存队列中,具体看代码。

<code class=" hljs java" style="box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; padding: 0.5em; color: rgb(0, 0, 0); border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; display: block; background-image: initial; background-attachment: initial; background-color: transparent !important; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;">    <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">public</span> Request <span class="hljs-title" style="box-sizing: border-box; color: rgb(136, 0, 0); font-weight: bold;">add</span>(Request request) {
        <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">// Tag the request as belonging to this queue and add it to the set of current requests.</span>
        request.setRequestQueue(<span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">this</span>);
        <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">synchronized</span> (mCurrentRequests) {
            mCurrentRequests.add(request);
        }

        <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">// Process requests in the order they are added.</span>
        request.setSequence(getSequenceNumber());
        request.addMarker(<span class="hljs-string" style="box-sizing: border-box; color: rgb(136, 0, 0);">"add-to-queue"</span>);

        <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">// If the request is uncacheable, skip the cache queue and go straight to the network.</span>
        <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">//判断请求是否需要缓存,如果不需要,直接添加到网络请求的队列中,结束下面的操作,如果需要缓存,则把请求添加到缓存队列中</span>
        <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">if</span> (!request.shouldCache()) {
            mNetworkQueue.add(request);
            <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">return</span> request;
        }

        <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">// Insert request into stage if there's already a request with the same cache key in flight.</span>
        <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">synchronized</span> (mWaitingRequests) {
            String cacheKey = request.getCacheKey();
            <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">if</span> (mWaitingRequests.containsKey(cacheKey)) {
                <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">// There is already a request in flight. Queue up.</span>
                Queue<Request> stagedRequests = mWaitingRequests.get(cacheKey);
                <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">if</span> (stagedRequests == <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">null</span>) {
                    stagedRequests = <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">new</span> LinkedList<Request>();
                }

                stagedRequests.add(request);
                mWaitingRequests.put(cacheKey, stagedRequests);
                <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">if</span> (VolleyLog.DEBUG) {
                    VolleyLog.v(<span class="hljs-string" style="box-sizing: border-box; color: rgb(136, 0, 0);">"Request for cacheKey=%s is in flight, putting on hold."</span>, cacheKey);
                }
            } <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">else</span> {
                <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">// Insert 'null' queue for this cacheKey, indicating there is now a request in</span>
                <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">// flight.</span>
                mWaitingRequests.put(cacheKey, <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">null</span>);
                mCacheQueue.add(request);
            }
            <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">return</span> request;
        }
    }</code>

所以如果需要缓存的话,一开始会从mCacheQueue.take()会得到执行,当不符合要求的时候,请求会添加到真正的网络请求队列中,以下是不符合要求的代码

<code class=" hljs avrasm" style="box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; padding: 0.5em; color: rgb(0, 0, 0); border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; display: block; background-image: initial; background-attachment: initial; background-color: transparent !important; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;">                //没有缓存
                if (entry == null) {
                    request<span class="hljs-preprocessor" style="box-sizing: border-box; color: rgb(136, 0, 0);">.addMarker</span>(<span class="hljs-string" style="box-sizing: border-box; color: rgb(136, 0, 0);">"cache-miss"</span>)<span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">;</span>
                    Log<span class="hljs-preprocessor" style="box-sizing: border-box; color: rgb(136, 0, 0);">.i</span>(<span class="hljs-string" style="box-sizing: border-box; color: rgb(136, 0, 0);">"CacheDispatcher"</span>, <span class="hljs-string" style="box-sizing: border-box; color: rgb(136, 0, 0);">"没有缓存数据:"</span> + request<span class="hljs-preprocessor" style="box-sizing: border-box; color: rgb(136, 0, 0);">.getUrl</span>())<span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">;</span>
                    mNetworkQueue<span class="hljs-preprocessor" style="box-sizing: border-box; color: rgb(136, 0, 0);">.put</span>(request)<span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">;</span>
                    continue<span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">;</span>
                }

                // If it is completely expired, just send it to the network.
                //缓存已过期
                if (entry<span class="hljs-preprocessor" style="box-sizing: border-box; color: rgb(136, 0, 0);">.isExpired</span>()) {
                    request<span class="hljs-preprocessor" style="box-sizing: border-box; color: rgb(136, 0, 0);">.addMarker</span>(<span class="hljs-string" style="box-sizing: border-box; color: rgb(136, 0, 0);">"cache-hit-expired"</span>)<span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">;</span>
                    request<span class="hljs-preprocessor" style="box-sizing: border-box; color: rgb(136, 0, 0);">.setCacheEntry</span>(entry)<span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">;</span>
                    Log<span class="hljs-preprocessor" style="box-sizing: border-box; color: rgb(136, 0, 0);">.i</span>(<span class="hljs-string" style="box-sizing: border-box; color: rgb(136, 0, 0);">"CacheDispatcher"</span>, <span class="hljs-string" style="box-sizing: border-box; color: rgb(136, 0, 0);">"缓存数据过期:"</span> + request<span class="hljs-preprocessor" style="box-sizing: border-box; color: rgb(136, 0, 0);">.getUrl</span>())<span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">;</span>
                    mNetworkQueue<span class="hljs-preprocessor" style="box-sizing: border-box; color: rgb(136, 0, 0);">.put</span>(request)<span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">;</span>
                    continue<span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">;</span>
                }</code>

如果缓存不符合要求,网络线程终止阻塞得到执行; 
我们一般习惯用法是在 Application 中全局初始化RequestQueue mRequestQueue,并启动它,让整个应用都能获取到。具体运用将会在下面用到。

三、Volley 实战 GET 请求和 POST 请求

这里我用酷狗音乐播放器中的一个音乐搜索功能的接口来实现这两种请求 
接口:http://mobilecdn.kugou.com/api/v3/search/song?keyword=冰雨 
返回数据: 
这里写图片描述
根据返回数据我们可以把基本数据类型定义出来

这里写图片描述SearchResult 就是整个数据的对象,ListSong 对应的是 Data 对象,SongDetail是info 下的每个 item 对象。 
1、GET 请求 
第一步:在 Application 中初始化RequestQueue,

<code class=" hljs cs" style="box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; padding: 0.5em; color: rgb(0, 0, 0); border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; display: block; background-image: initial; background-attachment: initial; background-color: transparent !important; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;">    <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">//初始化请求队列</span>
    <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">private</span> <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">void</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(136, 0, 0); font-weight: bold;">initRequestQueue</span>(){
        VollayUtil.initialize(mContext);
    }</code>
<code class=" hljs java" style="box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; padding: 0.5em; color: rgb(0, 0, 0); border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; display: block; background-image: initial; background-attachment: initial; background-color: transparent !important; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;"><span class="hljs-javadoc" style="box-sizing: border-box; color: rgb(136, 136, 255);">/**
 * Created by gyzhong on 15/3/1.
 */</span>
<span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(136, 0, 0); font-weight: bold;">VolleyUtil</span> {</span>

    <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">private</span> <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">static</span> RequestQueue mRequestQueue ;

    <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">public</span> <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">static</span> <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">void</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(136, 0, 0); font-weight: bold;">initialize</span>(Context context){
        <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">if</span> (mRequestQueue == <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">null</span>){
            <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">synchronized</span> (VolleyUtil.class){
                <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">if</span> (mRequestQueue == <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">null</span>){
                    mRequestQueue = Volley.newRequestQueue(context) ;
                }
            }
        }
        mRequestQueue.start();
    }

    <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">public</span> <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">static</span> RequestQueue <span class="hljs-title" style="box-sizing: border-box; color: rgb(136, 0, 0); font-weight: bold;">getRequestQueue</span>(){
        <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">if</span> (mRequestQueue == <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">null</span>)
            <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">throw</span> <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">new</span> RuntimeException(<span class="hljs-string" style="box-sizing: border-box; color: rgb(136, 0, 0);">"请先初始化mRequestQueue"</span>) ;
        <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">return</span> mRequestQueue ;
    }
}</code>

第二步:定制 Request 
先来分析接口所返回的数据,我们看到是一条 json 数据,虽然 Volley 中已经为我们定制好了JsonObjectRequest请求,但我们知道,在数据具体显示的时候,是需要把 json 数据转化为对象进行处理,所以这里我们可以定制通用的对象请求。如何定制呢? 
先看StringRequest的实现代码

<code class=" hljs axapta" style="box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; padding: 0.5em; color: rgb(0, 0, 0); border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; display: block; background-image: initial; background-attachment: initial; background-color: transparent !important; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;"><span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">//继承Request<String>,String 为请求解析之后的数据</span>
<span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(136, 0, 0); font-weight: bold;">StringRequest</span> <span class="hljs-inheritance" style="box-sizing: border-box;"><span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">extends</span></span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(136, 0, 0); font-weight: bold;">Request</span><<span class="hljs-title" style="box-sizing: border-box; color: rgb(136, 0, 0); font-weight: bold;">String</span>> {</span>
    <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">//正确数据回调接口</span>
    <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">private</span> <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">final</span> Listener<String> mListener;
    <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">public</span> StringRequest(<span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">int</span> method, String url, Listener<String> listener,
            ErrorListener errorListener) {
        <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">super</span>(method, url, errorListener);
        mListener = listener;
    }
    <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">public</span> StringRequest(String url, Listener<String> listener, ErrorListener errorListener) {
        <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">this</span>(Method.GET, url, listener, errorListener);
    }

    <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">//回调解析之后的数据</span>
    @Override
    <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">protected</span> <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">void</span> deliverResponse(String response) {
        mListener.onResponse(response);
    }

    <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">//解析数据,把网络请求,或者中缓存中获取的数据,解析成 String</span>
    @Override
    <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">protected</span> Response<String> parseNetworkResponse(NetworkResponse response) {
        String parsed;
        <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">try</span> {
            parsed = <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">new</span> String(response.data, HttpHeaderParser.parseCharset(response.headers));
        } <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">catch</span> (UnsupportedEncodingException e) {
            parsed = <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">new</span> String(response.data);
        }
        <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">return</span> Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response));
    }
}</code>

通过上面代码可知,StringRequest继承了 Request 并实现了两个抽象方法parseNetworkResponse()和 deliverResponse(),这两个方法很好理解,parseNetworkResponse()把获取到的数据解析成我们所定义的数据类型;deliverResponse()把所解析的数据通过回调接口回调给展示处。 
为了简化回调接口,这里把错误回调Response.ErrorListener 和正确的数据回调Response.Listener合并成一个ResponseListener

<code class=" hljs php" style="box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; padding: 0.5em; color: rgb(0, 0, 0); border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; display: block; background-image: initial; background-attachment: initial; background-color: transparent !important; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;"><span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">/**
 * Created by gyzhong on 15/3/1.
 * 简化回调接口
 */</span>
<span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">interface</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(136, 0, 0); font-weight: bold;">ResponseListener</span><<span class="hljs-title" style="box-sizing: border-box; color: rgb(136, 0, 0); font-weight: bold;">T</span>> <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">extends</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(136, 0, 0); font-weight: bold;">Response</span>.<span class="hljs-title" style="box-sizing: border-box; color: rgb(136, 0, 0); font-weight: bold;">ErrorListener</span>,<span class="hljs-title" style="box-sizing: border-box; color: rgb(136, 0, 0); font-weight: bold;">Response</span>.<span class="hljs-title" style="box-sizing: border-box; color: rgb(136, 0, 0); font-weight: bold;">Listener</span><<span class="hljs-title" style="box-sizing: border-box; color: rgb(136, 0, 0); font-weight: bold;">T</span>> {</span>
}</code>

根据 StringRequest,如法炮制

<code class=" hljs scala" style="box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; padding: 0.5em; color: rgb(0, 0, 0); border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; display: block; background-image: initial; background-attachment: initial; background-color: transparent !important; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;"><span class="hljs-javadoc" style="box-sizing: border-box; color: rgb(136, 136, 255);">/**
 * Created by gyzhong on 15/3/1.
 */</span>
public <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(136, 0, 0); font-weight: bold;">GetObjectRequest</span><<span class="hljs-title" style="box-sizing: border-box; color: rgb(136, 0, 0); font-weight: bold;">T</span>> <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">extends</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(136, 0, 0); font-weight: bold;">Request</span><<span class="hljs-title" style="box-sizing: border-box; color: rgb(136, 0, 0); font-weight: bold;">T</span>> {</span>

    <span class="hljs-javadoc" style="box-sizing: border-box; color: rgb(136, 136, 255);">/**
     * 正确数据的时候回掉用
     */</span>
    <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">private</span> ResponseListener mListener ;
    <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">/*用来解析 json 用的*/</span>
    <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">private</span> Gson mGson ;
    <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">/*在用 gson 解析 json 数据的时候,需要用到这个参数*/</span>
    <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">private</span> Type mClazz ;

    public GetObjectRequest(String url,Type <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">type</span>, ResponseListener listener) {
        <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">super</span>(Method.GET, url, listener);
        <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">this</span>.mListener = listener ;
        mGson = <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">new</span> GsonBuilder().excludeFieldsWithoutExposeAnnotation().create() ;
        mClazz = <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">type</span> ;
    }

    <span class="hljs-javadoc" style="box-sizing: border-box; color: rgb(136, 136, 255);">/**
     * 这里开始解析数据
     * <span class="hljs-javadoctag" style="box-sizing: border-box; font-weight: bold;">@param</span> response Response from the network
     * <span class="hljs-javadoctag" style="box-sizing: border-box; font-weight: bold;">@return</span>
     */</span>
    <span class="hljs-annotation" style="box-sizing: border-box; color: rgb(136, 136, 136);">@Override</span>
    <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">protected</span> Response<T> parseNetworkResponse(NetworkResponse response) {
        <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">try</span> {
            T result ;
            String jsonString =
                    <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">new</span> String(response.data, HttpHeaderParser.parseCharset(response.headers));
            result = mGson.fromJson(jsonString,mClazz) ;
            <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">return</span> Response.success(result,
                    HttpHeaderParser.parseCacheHeaders(response));
        } <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">catch</span> (UnsupportedEncodingException e) {
            <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">return</span> Response.error(<span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">new</span> ParseError(e));
        }
    }

    <span class="hljs-javadoc" style="box-sizing: border-box; color: rgb(136, 136, 255);">/**
     * 回调正确的数据
     * <span class="hljs-javadoctag" style="box-sizing: border-box; font-weight: bold;">@param</span> response The parsed response returned by
     */</span>
    <span class="hljs-annotation" style="box-sizing: border-box; color: rgb(136, 136, 136);">@Override</span>
    <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">protected</span> void deliverResponse(T response) {
        mListener.onResponse(response);
    }
}</code>

以上代码中在实例化 Gson 的时候用到的是mGson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation(),主要是用于过滤字段用的.如果有疑问的同学可以参考我前面写的一篇文章Gson 过滤字段的几种方法 
第三步:获取 request

<code class=" hljs vbscript" style="box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; padding: 0.5em; color: rgb(0, 0, 0); border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; display: block; background-image: initial; background-attachment: initial; background-color: transparent !important; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;"><span class="hljs-built_in" style="box-sizing: border-box; font-weight: bold;">Request</span> <span class="hljs-built_in" style="box-sizing: border-box; font-weight: bold;">request</span> = <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">new</span> GetObjectRequest(url,<span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">new</span> TypeToken<SearchResult>(){}.getType(),listener) ;</code>

1、url -> http://mobilecdn.kugou.com/api/v3/search/song?keyword=冰雨 
2、new TypeToken(){}.getType() ->为 gson 解析 json 数据所要的 type 
3、listener -> 为我们定义的ResponseListener回调接口 
第四步:添加请求到队列中

<code class=" hljs avrasm" style="box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; padding: 0.5em; color: rgb(0, 0, 0); border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; display: block; background-image: initial; background-attachment: initial; background-color: transparent !important; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;">VolleyUtil<span class="hljs-preprocessor" style="box-sizing: border-box; color: rgb(136, 0, 0);">.getRequestQueue</span>()<span class="hljs-preprocessor" style="box-sizing: border-box; color: rgb(136, 0, 0);">.add</span>(request) <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">;</span></code>

所以,此接口的代码即为

<code class=" hljs java" style="box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; padding: 0.5em; color: rgb(0, 0, 0); border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; display: block; background-image: initial; background-attachment: initial; background-color: transparent !important; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;">    <span class="hljs-javadoc" style="box-sizing: border-box; color: rgb(136, 136, 255);">/**
     * 酷狗音乐搜索音乐get网络请求接口
     *<span class="hljs-javadoctag" style="box-sizing: border-box; font-weight: bold;"> @param</span> keyWord 要搜索的关键字
     *<span class="hljs-javadoctag" style="box-sizing: border-box; font-weight: bold;"> @param</span> listener 回调接口,包含错误回调和正确的数据回调
     */</span>
    <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">public</span> <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">static</span> <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">void</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(136, 0, 0); font-weight: bold;">getObjectSearchApi</span>(String keyWord,ResponseListener listener){
        String url ;
        <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">try</span> {
            url = Constant.Host+<span class="hljs-string" style="box-sizing: border-box; color: rgb(136, 0, 0);">"?keyword="</span>+ URLEncoder.encode(keyWord,<span class="hljs-string" style="box-sizing: border-box; color: rgb(136, 0, 0);">"utf-8"</span>) ;
        } <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">catch</span> (UnsupportedEncodingException e) {
            e.printStackTrace();
            url = Constant.Host+<span class="hljs-string" style="box-sizing: border-box; color: rgb(136, 0, 0);">"?keyword="</span>+ URLEncoder.encode(keyWord) ;
        }
        Request request = <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">new</span> GetObjectRequest(url,<span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">new</span> TypeToken<SearchResult>(){}.getType(),listener) ;
        VollayUtil.getRequestQueue().add(request) ;
    }</code>

第五步:代码测试

<code class=" hljs java" style="box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; padding: 0.5em; color: rgb(0, 0, 0); border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; display: block; background-image: initial; background-attachment: initial; background-color: transparent !important; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;"><span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(136, 0, 0); font-weight: bold;">GetRequestActivity</span> <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">extends</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(136, 0, 0); font-weight: bold;">ActionBarActivity</span> {</span>

    <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">private</span> ListView mListView ;
    <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">private</span> SongAdapter mAdapter ;
    <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">private</span> List<SongDetail> mSongList ;
    <span class="hljs-annotation" style="box-sizing: border-box; color: rgb(136, 136, 136);">@Override</span>
    <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">protected</span> <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">void</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(136, 0, 0); font-weight: bold;">onCreate</span>(Bundle savedInstanceState) {
        <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">super</span>.onCreate(savedInstanceState);
        setContentView(R.layout.activity_get);
        mSongList = <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">new</span> ArrayList<SongDetail>() ;
        mListView = (ListView) findViewById(R.id.id_list_view);
        mAdapter = <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">new</span> SongAdapter(<span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">this</span>,mSongList) ;
        mListView.setAdapter(mAdapter);
        <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">/*请求网络获取数据*/</span>
        KugouApi.getObjectSearchApi(<span class="hljs-string" style="box-sizing: border-box; color: rgb(136, 0, 0);">"冰雨"</span>,<span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">new</span> ResponseListener<SearchResult>() {
            <span class="hljs-annotation" style="box-sizing: border-box; color: rgb(136, 136, 136);">@Override</span>
            <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">public</span> <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">void</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(136, 0, 0); font-weight: bold;">onErrorResponse</span>(VolleyError error) {
                Log.v(<span class="hljs-string" style="box-sizing: border-box; color: rgb(136, 0, 0);">"zgy"</span>,<span class="hljs-string" style="box-sizing: border-box; color: rgb(136, 0, 0);">"======onErrorResponse====="</span>+error);
            }

            <span class="hljs-annotation" style="box-sizing: border-box; color: rgb(136, 136, 136);">@Override</span>
            <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">public</span> <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">void</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(136, 0, 0); font-weight: bold;">onResponse</span>(SearchResult response) {
                Log.v(<span class="hljs-string" style="box-sizing: border-box; color: rgb(136, 0, 0);">"zgy"</span>,<span class="hljs-string" style="box-sizing: border-box; color: rgb(136, 0, 0);">"======onResponse====="</span>+response);
                mSongList.addAll(response.getData().getInfo()) ;
                mAdapter.notifyDataSetChanged();
            }
        });
    }

}</code>

测试效果图如下: 
这里写图片描述 这里写图片描述 
可以看到和我们在浏览器中请求的数据一模一样!

2、POST请求 
因为在讲 get 请求的时候花了很大篇幅讲原理,所以在 post 请求的时候,需要注意的东西相对来说比较少, 不管是 get 请求还是 post 请求,实现步骤是不会变。 这里post 请求,我们也是用酷狗搜索音乐的这个 api 来测试! 
在前面我们已经讲到了,在同一个应用中共用同一个 RequestQueue,所以第一步可以省略,因为我们已经实现过了。这里直接到定制Request,我们在学习网络编程的时候就已经知道,用 GET方式请求,请求的数据是直接跟在 URL的后面用”?”去分开了,如果有多个数据则用”&”分开。而 POST则把数据直接封装在HTTP的包体中,两者各有优缺点,自己衡量着用。 
因为 api 接口还是同一个,所以返回的数据类型肯定是一样的,在解析数据的时候就可以和 GetObjectRequest 复用,所以 PostObjectRequest 的实现可以通过继承GetObjectRequest的方式,也可以直接拷贝一份出来,为了更好的区分,我这里就直接拷贝一份,然后再稍加修改。

<code class=" hljs scala" style="box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; padding: 0.5em; color: rgb(0, 0, 0); border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; display: block; background-image: initial; background-attachment: initial; background-color: transparent !important; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;"><span class="hljs-javadoc" style="box-sizing: border-box; color: rgb(136, 136, 255);">/**
 * Created by gyzhong on 15/3/1.
 */</span>
public <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(136, 0, 0); font-weight: bold;">PostObjectRequest</span><<span class="hljs-title" style="box-sizing: border-box; color: rgb(136, 0, 0); font-weight: bold;">T</span>> <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">extends</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(136, 0, 0); font-weight: bold;">Request</span><<span class="hljs-title" style="box-sizing: border-box; color: rgb(136, 0, 0); font-weight: bold;">T</span>> {</span>

    <span class="hljs-javadoc" style="box-sizing: border-box; color: rgb(136, 136, 255);">/**
     * 正确数据的时候回掉用
     */</span>
    <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">private</span> ResponseListener mListener ;
    <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">/*用来解析 json 用的*/</span>
    <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">private</span> Gson mGson ;
    <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">/*在用 gson 解析 json 数据的时候,需要用到这个参数*/</span>
    <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">private</span> Type mClazz ;
    <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">/*请求 数据通过参数的形式传入*/</span>
    <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">private</span> Map<String,String> mParams;
    <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">//需要传入参数,并且请求方式不能再为 get,改为 post</span>
    public PostObjectRequest(String url, Map<String,String> params,Type <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">type</span>, ResponseListener listener) {
        <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">super</span>(Method.POST, url, listener);
        <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">this</span>.mListener = listener ;
        mGson = <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">new</span> GsonBuilder().excludeFieldsWithoutExposeAnnotation().create() ;
        mClazz = <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">type</span> ;
        setShouldCache(<span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">false</span>);
        mParams = params ;
    }

    <span class="hljs-javadoc" style="box-sizing: border-box; color: rgb(136, 136, 255);">/**
     * 这里开始解析数据
     * <span class="hljs-javadoctag" style="box-sizing: border-box; font-weight: bold;">@param</span> response Response from the network
     * <span class="hljs-javadoctag" style="box-sizing: border-box; font-weight: bold;">@return</span>
     */</span>
    <span class="hljs-annotation" style="box-sizing: border-box; color: rgb(136, 136, 136);">@Override</span>
    <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">protected</span> Response<T> parseNetworkResponse(NetworkResponse response) {
        <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">try</span> {
            T result ;
            String jsonString =
                    <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">new</span> String(response.data, HttpHeaderParser.parseCharset(response.headers));
            Log.v(<span class="hljs-string" style="box-sizing: border-box; color: rgb(136, 0, 0);">"zgy"</span>, <span class="hljs-string" style="box-sizing: border-box; color: rgb(136, 0, 0);">"====SearchResult==="</span> + jsonString);
            result = mGson.fromJson(jsonString,mClazz) ;
            <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">return</span> Response.success(result,
                    HttpHeaderParser.parseCacheHeaders(response));
        } <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">catch</span> (UnsupportedEncodingException e) {
            <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">return</span> Response.error(<span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">new</span> ParseError(e));
        }
    }

    <span class="hljs-javadoc" style="box-sizing: border-box; color: rgb(136, 136, 255);">/**
     * 回调正确的数据
     * <span class="hljs-javadoctag" style="box-sizing: border-box; font-weight: bold;">@param</span> response The parsed response returned by
     */</span>
    <span class="hljs-annotation" style="box-sizing: border-box; color: rgb(136, 136, 136);">@Override</span>
    <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">protected</span> void deliverResponse(T response) {
        mListener.onResponse(response);
    }

<span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">//关键代码就在这里,在 Volley 的网络操作中,如果判断请求方式为 Post 则会通过此方法来获取 param,所以在这里返回我们需要的参数,</span>
    <span class="hljs-annotation" style="box-sizing: border-box; color: rgb(136, 136, 136);">@Override</span>
    <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">protected</span> Map<String, String> getParams() <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">throws</span> AuthFailureError {
        <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">return</span> mParams;
    }
}</code>

再来看看 api 接口怎么实现,

<code class=" hljs java" style="box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; padding: 0.5em; color: rgb(0, 0, 0); border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; display: block; background-image: initial; background-attachment: initial; background-color: transparent !important; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;">    <span class="hljs-javadoc" style="box-sizing: border-box; color: rgb(136, 136, 255);">/**
     * 酷狗音乐搜索音乐post网络请求接口
     *<span class="hljs-javadoctag" style="box-sizing: border-box; font-weight: bold;"> @param</span> keyword 要搜索的关键字
     *<span class="hljs-javadoctag" style="box-sizing: border-box; font-weight: bold;"> @param</span> listener 回调接口,包含错误回调和正确的数据回调
     */</span>
    <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">public</span> <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">static</span> <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">void</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(136, 0, 0); font-weight: bold;">postObjectSearchApi</span>(String keyword,ResponseListener listener){
        Map<String,String> param = <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">new</span> HashMap<String,String>() ;
        param.put(<span class="hljs-string" style="box-sizing: border-box; color: rgb(136, 0, 0);">"keyword"</span>,keyword) ;
        Request request = <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">new</span> PostObjectRequest(Constant.Host,param,<span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">new</span> TypeToken<SearchResult>(){}.getType(),listener);
        VolleyUtil.getRequestQueue().add(request) ;
    }</code>

跟 get 请求还是很相似的,只是在实例化 Request 的时候多传入了一个param参数,并且 url 不能再是包含请求数据的 url。 
接口 api测试代码

<code class=" hljs java" style="box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; padding: 0.5em; color: rgb(0, 0, 0); border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; display: block; background-image: initial; background-attachment: initial; background-color: transparent !important; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;"><span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(136, 0, 0); font-weight: bold;">PostRequestActivity</span> <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">extends</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(136, 0, 0); font-weight: bold;">ActionBarActivity</span> {</span>

    <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">private</span> ListView mListView ;
    <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">private</span> SongAdapter mAdapter ;
    <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">private</span> List<SongDetail> mSongList ;
    <span class="hljs-annotation" style="box-sizing: border-box; color: rgb(136, 136, 136);">@Override</span>
    <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">protected</span> <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">void</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(136, 0, 0); font-weight: bold;">onCreate</span>(Bundle savedInstanceState) {
        <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">super</span>.onCreate(savedInstanceState);
        setContentView(R.layout.activity_post);
        mSongList = <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">new</span> ArrayList<SongDetail>() ;
        mListView = (ListView) findViewById(R.id.id_list_view);
        mAdapter = <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">new</span> SongAdapter(<span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">this</span>,mSongList) ;
        mListView.setAdapter(mAdapter);
        <span class="hljs-comment" style="box-sizing: border-box; color: rgb(136, 136, 136);">/*请求网络获取数据*/</span>
        KugouApi.postObjectSearchApi(<span class="hljs-string" style="box-sizing: border-box; color: rgb(136, 0, 0);">"冰雨"</span>, <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">new</span> moon.vollay.network.ResponseListener<SearchResult>() {
            <span class="hljs-annotation" style="box-sizing: border-box; color: rgb(136, 136, 136);">@Override</span>
            <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">public</span> <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">void</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(136, 0, 0); font-weight: bold;">onErrorResponse</span>(VolleyError error) {
                Log.v(<span class="hljs-string" style="box-sizing: border-box; color: rgb(136, 0, 0);">"zgy"</span>, <span class="hljs-string" style="box-sizing: border-box; color: rgb(136, 0, 0);">"======onErrorResponse====="</span> + error);
            }

            <span class="hljs-annotation" style="box-sizing: border-box; color: rgb(136, 136, 136);">@Override</span>
            <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">public</span> <span class="hljs-keyword" style="box-sizing: border-box; font-weight: bold;">void</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(136, 0, 0); font-weight: bold;">onResponse</span>(SearchResult response) {
                Log.v(<span class="hljs-string" style="box-sizing: border-box; color: rgb(136, 0, 0);">"zgy"</span>, <span class="hljs-string" style="box-sizing: border-box; color: rgb(136, 0, 0);">"======onResponse====="</span> + response);
                mSongList.addAll(response.getData().getInfo());
                mAdapter.notifyDataSetChanged();
            }
        });
    }

}</code>

post测试效果图如下: 
这里写图片描述 这里写图片描述 
数据显示跟 get 请求完全相同;ok,以上就是 Volley GET请求和 POST请求的全部内容!接下来又到了总结的时候

四、总结

1、volley 适用于轻量高并发的网络请求,这里补充一个知识点,因为 Volley 请求网络的数据全部保存在内存中,所以 volley 不适合请求较大的数据,比如下载文件,下载大图片等。

2、volley 的使用遵循四个步骤 
a、RequestQueue mRequestQueue = Vollay.newRequestQueue(Context context) ; 
b、mRequestQueue.start() 
c、Request mRequest = new ObjectRequst(…) 
d、mRequestQueue.add(mRequest)

3、同一个程序中最好共用一个 RequestQueue。

4、可以根据接口的放回数据类型定制任意的 Request,volley 已经默认为我们实现了 StringRequest、JsonArrayRequest、JsonObjectRequest、ImageRequest四个请求类型。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值