zoukankan      html  css  js  c++  java
  • Android网络通信Volley框架源代码浅析(二)


    尊重原创 http://write.blog.csdn.net/postedit/25921795

    在前面的一片文章Volley框架浅析(一)中我们知道在RequestQueue这个类中,有两个队列:本地队列和网络队列

    /** The cache triage queue. */
        private final PriorityBlockingQueue<Request<?>> mCacheQueue =
            new PriorityBlockingQueue<Request<?

    >>(); /** The queue of requests that are actually going out to the network. */ private final PriorityBlockingQueue<Request<?>> mNetworkQueue = new PriorityBlockingQueue<Request<?

    >>();


    与之相应的分别有本地线程和网络线程。通过对RequestQueue源代码的分析,本地线程有一条。而网络线程默认有四条,我们能够对网络线程的个数进行设置,我们首先来学习一下本地线程:

    (1) CacheDispatcher.java

    public class CacheDispatcher extends Thread {
    
        private static final boolean DEBUG = VolleyLog.DEBUG;
    
    	//本地队列,从RequestQueue中传递进来的
        private final BlockingQueue<Request<?>> mCacheQueue;
    
        //网络请求队列。也是从RequestQueue中传递进来,当本地缓存没有命中时。须要把请求从本地队列增加网络队列
        private final BlockingQueue<Request<?>> mNetworkQueue;
    
        //磁盘缓存对象
        private final Cache mCache;
    
        //就是用于从子线程向Ui线程发送数据
        private final ResponseDelivery mDelivery;
    
        /** Used for telling us to die. */
        private volatile boolean mQuit = false;
    
        /**
         * Creates a new cache triage dispatcher thread.  You must call {@link #start()}
         * in order to begin processing.
         *
         * @param cacheQueue Queue of incoming requests for triage
         * @param networkQueue Queue to post requests that require network to
         * @param cache Cache interface to use for resolution
         * @param delivery Delivery interface to use for posting responses
         */
        public CacheDispatcher(
                BlockingQueue<Request<?

    >> cacheQueue, BlockingQueue<Request<?

    >> networkQueue, Cache cache, ResponseDelivery delivery) { mCacheQueue = cacheQueue; mNetworkQueue = networkQueue; mCache = cache; mDelivery = delivery; } /** * Forces this dispatcher to quit immediately. If any requests are still in * the queue, they are not guaranteed to be processed. */ public void quit() { mQuit = true; interrupt(); } @Override public void run() { if (DEBUG) VolleyLog.v("start new dispatcher"); Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); // 缓存初始化,将磁盘中的数据读入内存 mCache.initialize(); while (true) { try { // 堵塞式从队列中取出请求 final Request<?> request = mCacheQueue.take(); request.addMarker("cache-queue-take"); // 推断request是否被取消了(调用cancel方法)。假设取消了就不运行,再次到队列中取请求 if (request.isCanceled()) { request.finish("cache-discard-canceled"); continue; } // 从缓存中读取数据 Cache.Entry entry = mCache.get(request.getCacheKey()); if (entry == null) { //没有命中 request.addMarker("cache-miss"); // 没有命中时,就将请求放入网络队列 mNetworkQueue.put(request); continue; } // 数据已经过期,将请求放入网络队列 if (entry.isExpired()) { request.addMarker("cache-hit-expired"); request.setCacheEntry(entry); mNetworkQueue.put(request); continue; } // 本地命中 request.addMarker("cache-hit"); Response<?> response = request.parseNetworkResponse( new NetworkResponse(entry.data, entry.responseHeaders)); request.addMarker("cache-hit-parsed"); if (!entry.refreshNeeded()) { // Completely unexpired cache hit. Just deliver the response. //命中,而且不须要刷新 mDelivery.postResponse(request, response); } else { //命中,须要刷新,将请求放入网络队列,这里面的代码事实上能够依据需求自己重写 // Soft-expired cache hit. We can deliver the cached response, // but we need to also send the request to the network for // refreshing. request.addMarker("cache-hit-refresh-needed"); request.setCacheEntry(entry); // Mark the response as intermediate. response.intermediate = true; // Post the intermediate response back to the user and have // the delivery then forward the request along to the network. mDelivery.postResponse(request, response, new Runnable() { @Override public void run() { try { mNetworkQueue.put(request); } catch (InterruptedException e) { // Not much we can do about this. } } }); } } catch (InterruptedException e) { // We may have been interrupted because it was time to quit. if (mQuit) { return; } continue; } } } }


    (2) NetworkDispatcher.java

    public class NetworkDispatcher extends Thread {
        /** 网络队列 */
        private final BlockingQueue<Request<?

    >> mQueue; /** 用于Http请求,依据前面的学习,他事实上使用的是HttpURLConnection或者HttpClient. */ private final Network mNetwork; /** 本地缓存,网络请求成功后。放入缓存. */ private final Cache mCache; /** For posting responses and errors. */ private final ResponseDelivery mDelivery; /** Used for telling us to die. */ private volatile boolean mQuit = false; /** * Creates a new network dispatcher thread. You must call {@link #start()} * in order to begin processing. * * @param queue Queue of incoming requests for triage * @param network Network interface to use for performing requests * @param cache Cache interface to use for writing responses to cache * @param delivery Delivery interface to use for posting responses */ public NetworkDispatcher(BlockingQueue<Request<?

    >> queue, Network network, Cache cache, ResponseDelivery delivery) { mQueue = queue; mNetwork = network; mCache = cache; mDelivery = delivery; } /** * Forces this dispatcher to quit immediately. If any requests are still in * the queue, they are not guaranteed to be processed. */ public void quit() { mQuit = true; interrupt(); } @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) private void addTrafficStatsTag(Request<?> request) { // Tag the request (if API >= 14) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { TrafficStats.setThreadStatsTag(request.getTrafficStatsTag()); } } @Override public void run() { Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); Request<?

    > request; while (true) { try { // 从队列中堵塞式取出一个请求. request = mQueue.take(); } catch (InterruptedException e) { // We may have been interrupted because it was time to quit. if (mQuit) { return; } continue; } try { request.addMarker("network-queue-take"); // 同理须要推断是否取消,假设取消运行下一个请求 if (request.isCanceled()) { request.finish("network-discard-cancelled"); continue; } addTrafficStatsTag(request); // 通过NetWork的perfromRequest方法放回一个NetworkResponse对象 NetworkResponse networkResponse = mNetwork.performRequest(request); request.addMarker("network-http-complete"); // 假设这个返回结果已经发送到了ui线程。就将它finish if (networkResponse.notModified && request.hasHadResponseDelivered()) { request.finish("not-modified"); continue; } // 将NetworkResponse 解析成Response. Response<?> response = request.parseNetworkResponse(networkResponse); request.addMarker("network-parse-complete"); // 假设须要缓存。那么将结果存入缓存 if (request.shouldCache() && response.cacheEntry != null) { mCache.put(request.getCacheKey(), response.cacheEntry); request.addMarker("network-cache-written"); } // 标记为已经发送 request.markDelivered(); //将数据发送到Ui线程 mDelivery.postResponse(request, response); } catch (VolleyError volleyError) { parseAndDeliverNetworkError(request, volleyError); } catch (Exception e) { VolleyLog.e(e, "Unhandled exception %s", e.toString()); mDelivery.postError(request, new VolleyError(e)); } } } private void parseAndDeliverNetworkError(Request<?

    > request, VolleyError error) { error = request.parseNetworkError(error); mDelivery.postError(request, error); } }

    通过上面的代码,我们来总结一下一个请求的运行过程吧:
    1、一个请求就是一个Request对象,首先将Request对象增加到RequestQueue中.
    2、推断Request能否够缓存,假设能够。则增加到本地缓存队列,否则增加网络队列
    3、本地线程不断监听本地队列是否有请求。假设有请求取出来
    4、推断Request是否取消,假设取消,处理下一个请求
    5、推断缓存是否命中,假设没有命中。将该请求增加网络队列
    6、假设命中,可是过期,相同将该请求增加网络队列
    7、假设命中。而且不用刷新,那么直接放回结果。不用增加网络队列
    8、假设命中,而且须要刷新。那么放回结果,而且增加网络队列
    9、相同4条网络线程也在不断监听网络队列是否有请求,一旦发现有请求,取出请求,推断是否取消,假设取消。那么取出下一个请求
    10、假设没有取消,那么通过NetWork进行http请求,将请求结果封装成NetworkResponse,然后转换为Response
    11、假设能够缓存,那么将数据写入缓存
    12、通过Delivery将Response返回到ui线程



    通过以上12步,完毕了一个完整的请求

    研究了这么久。我们还没有研究Request和Response是什么呢,假设熟悉http请求的同学相信非常好理解。
    Request就是一个http请求。Response就是http返回的内容,先看看Request这个类吧
    Request是一个抽象类。我仅仅介绍比較重要的几个方法:

    public abstract class Request<T> implements Comparable<Request<T>> {
    	//Http 请求方法 POST,GET
        private final int mMethod;
    
        /** 请求URL*/
        private final String mUrl;
    	//用于出错时的回调接口
        private final Response.ErrorListener mErrorListener;
    
        /** 这个请求在队列中的顺序 */
        private Integer mSequence;
    
       ...
    
        /** 是否可以缓存 */
        private boolean mShouldCache = true;
    
        /** 是否已经取消了,网络线程和本地线程都会对此推断,假设取消了就不请求了 */
        private boolean mCanceled = false;
    
        /** 请求策略,比方设置最大重试次数之类的*/
        private RetryPolicy mRetryPolicy;
    
        /**
         * Creates a new request with the given method (one of the values from {@link Method}),
         * URL, and error listener.  Note that the normal response listener is not provided here as
         * delivery of responses is provided by subclasses, who have a better idea of how to deliver
         * an already-parsed response.
         */
        public Request(int method, String url, Response.ErrorListener listener) {
            mMethod = method;
            mUrl = url;
            mErrorListener = listener;
            setRetryPolicy(new DefaultRetryPolicy());
    
            mDefaultTrafficStatsTag = findDefaultTrafficStatsTag(url);
        }
    
      
        /**
         * Sets the retry policy for this request.
         *
         * @return This Request object to allow for chaining.
         */
        public Request<?> setRetryPolicy(RetryPolicy retryPolicy) {
            mRetryPolicy = retryPolicy;
            return this;
        }
       
       ...
    
        /**
         * 通过此方法取消一个请求
         */
        public void cancel() {
            mCanceled = true;
        }
    
        /**
         * 推断是否已经取消.
         */
        public boolean isCanceled() {
            return mCanceled;
        }
    
        /**
         * 获取请求头
         * @throws AuthFailureError In the event of auth failure
         */
        public Map<String, String> getHeaders() throws AuthFailureError {
            return Collections.emptyMap();
        }
    
        /**
         * Returns a Map of POST parameters to be used for this request, or null if
         * a simple GET should be used.  Can throw {@link AuthFailureError} as
         * authentication may be required to provide these values.
         *
         * <p>Note that only one of getPostParams() and getPostBody() can return a non-null
         * value.</p>
         * @throws AuthFailureError In the event of auth failure
         *
         * @deprecated Use {@link #getParams()} instead.
         */
        @Deprecated
        protected Map<String, String> getPostParams() throws AuthFailureError {
            return getParams();
        }
       
    
        /**
         * Returns a Map of parameters to be used for a POST or PUT request.  Can throw
         * {@link AuthFailureError} as authentication may be required to provide these values.
         *
         * <p>Note that you can directly override {@link #getBody()} for custom data.</p>
         *
         * @throws AuthFailureError in the event of auth failure
         */
        protected Map<String, String> getParams() throws AuthFailureError {
            return null;
        }
    
      
    
        public String getBodyContentType() {
            return "application/x-www-form-urlencoded; charset=" + getParamsEncoding();
        }
    
        
        
    
        /**
         * 设置是否能缓存
         *
         * @return This Request object to allow for chaining.
         */
        public final Request<?

    > setShouldCache(boolean shouldCache) { mShouldCache = shouldCache; return this; } /** * 推断是否可以缓存 */ public final boolean shouldCache() { return mShouldCache; } /** * 这是个抽象方法,我们必须实现,用于将NetworkResponse 转化为Response * @param response Response from the network * @return The parsed response, or null in the case of an error */ abstract protected Response<T> parseNetworkResponse(NetworkResponse response); /** * 这个我们也必须实现,用于将Response发送到ui线程 * @param response The parsed response returned by * {@link #parseNetworkResponse(NetworkResponse)} */ abstract protected void deliverResponse(T response); } 以下继续看看Response这个类: public class Response<T> { /** 成功的时候回调. */ public interface Listener<T> { /** Called when a response is received. */ public void onResponse(T response); } /** 失败的时候回调 */ public interface ErrorListener { /** * Callback method that an error has been occurred with the * provided error code and optional user-readable message. */ public void onErrorResponse(VolleyError error); } /** 成功的时候创建一个Response. */ public static <T> Response<T> success(T result, Cache.Entry cacheEntry) { return new Response<T>(result, cacheEntry); } /** * 失败的时候创建一个Response */ public static <T> Response<T> error(VolleyError error) { return new Response<T>(error); } /** Parsed response, or null in the case of error. */ public final T result; /** * Returns whether this response is considered successful. */ public boolean isSuccess() { return error == null; } //私有的,我们无法调用 private Response(T result, Cache.Entry cacheEntry) { this.result = result; this.cacheEntry = cacheEntry; this.error = null; } private Response(VolleyError error) { this.result = null; this.cacheEntry = null; this.error = error; } }


    学习了上面两个类后,我们须要知道例如以下知识:
    Volley中的不论什么请求都是继承Request的。如Volley提供的StringRequest,JsonArrayRequest,JsonObjectRequest
    ImageRequest等等。而且要实现当中的两个方法
    abstract protected Response<T> parseNetworkResponse(NetworkResponse response);

    abstract protected void deliverResponse(T response);

    T是泛型,StringRequest中T表示String,后期我将会简介这几种Request的使用,敬请大家期待。。



    最后在介绍一个接口,就是ResponseDelivery.java

    它的一个实现类是ExecutorDelivery.java


    public class ExecutorDelivery implements ResponseDelivery {
        /** 执行已提交的 Runnable 任务的对象。此接口提供一种将任务提交与每一个任务将怎样执行的机制(包含线程使用的细节、调度等)分离开来的方法。在线程池中经经常使用到 */
        private final Executor mResponsePoster;
    
        /**
         * 传入一个Handler,事实上就是执行在主线的Handler。我想你应该明确为什么他可以从子线程
    	 将数据传入ui线程了
         * @param handler {@link Handler} to post responses on
         */
        public ExecutorDelivery(final Handler handler) {
            // Make an Executor that just wraps the handler.
            mResponsePoster = new Executor() {
                @Override
                public void execute(Runnable command) {
    				//这里调用了handler的post方法
                    handler.post(command);
                }
            };
        }
    
        /**
         * Creates a new response delivery interface, mockable version
         * for testing.
         * @param executor For running delivery tasks
         */
        public ExecutorDelivery(Executor executor) {
            mResponsePoster = executor;
        }
    
        @Override
        public void postResponse(Request<?> request, Response<?> response) {
            postResponse(request, response, null);
        }
    
        @Override
        public void postResponse(Request<?> request, Response<?> response, Runnable runnable) {
            request.markDelivered();
            request.addMarker("post-response");
            mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, runnable));
        }
    
      
        /**
         * A Runnable used for delivering network responses to a listener on the
         * main thread.
         */
        @SuppressWarnings("rawtypes")
        private class ResponseDeliveryRunnable implements Runnable {
            private final Request mRequest;
            private final Response mResponse;
            private final Runnable mRunnable;
    
            public ResponseDeliveryRunnable(Request request, Response response, Runnable runnable) {
                mRequest = request;
                mResponse = response;
                mRunnable = runnable;
            }
    
            @SuppressWarnings("unchecked")
            @Override
            public void run() {
                // If this request has canceled, finish it and don't deliver.
                if (mRequest.isCanceled()) {
                    mRequest.finish("canceled-at-delivery");
                    return;
                }
    
                // Deliver a normal response or error, depending.
                if (mResponse.isSuccess()) {
    				//在这里调用了deliverResponse
                    mRequest.deliverResponse(mResponse.result);
                } else {
                    mRequest.deliverError(mResponse.error);
                }
    
                // If this is an intermediate response, add a marker, otherwise we're done
                // and the request can be finished.
                if (mResponse.intermediate) {
                    mRequest.addMarker("intermediate-response");
                } else {
                    mRequest.finish("done");
                }
    
                // If we have been provided a post-delivery runnable, run it.
                if (mRunnable != null) {
                    mRunnable.run();
                }
           }
        }
    }

    好了,今天就写到这里吧,大家有什么不明确的欢迎留言讨论....


  • 相关阅读:
    【百度地图API】如何快速创建带有标注的地图?——快速创建地图工具+如何标注商家
    【百度地图API】百度做了一个艰难的决定——取消密钥机制!!
    【设计师工具】3个好用的在线配色工具
    【百度地图API】建立全国银行位置查询系统(二)——怎样为地图添加控件
    【百度地图API】如何在地图上添加标注?——另有:坐标拾取工具+打车费用接口介绍
    【百度地图API】多家地图API文件大小对比
    “街坊”房产数字平台,昔日的思想,曾经的努力
    软件工程之感想
    .net执行性能,Winform性能优化?如何提高.net程序性能
    个人之思考整理
  • 原文地址:https://www.cnblogs.com/hrhguanli/p/5085294.html
Copyright © 2011-2022 走看看