zoukankan      html  css  js  c++  java
  • Android Volley分析(一)——结构

    Volley是Android系统下的一个网络通信库。为Android提供简单高速的网络操作(Volley:Esay, Fast Networking for Android),以下是它的结构:


    既然是网络通信库,自然会涉及到网络的基础操作:请求和响应。也是最主要的概念。client发出请求。服务端返回响应的字节数据。client解析得到想要的结果。Volley怎么设计这些主要的概念?

    一、组件

    1、Network

    网络操作的定义,传入请求Request,得到响应NetworkResponse

    public interface Network {
        /**
         * Performs the specified request.
         * @param request Request to process
         * @return A {@link NetworkResponse} with data and caching metadata; will never be null
         * @throws VolleyError on errors
         */
        public NetworkResponse performRequest(Request<?

    > request) throws VolleyError; }


    2、Request

    请求的定义,包括网络请求的參数、地址等信息

    public Request(int method, String url, Response.ErrorListener listener) {
            mMethod = method;
            mUrl = url;
            mErrorListener = listener;
            setRetryPolicy(new DefaultRetryPolicy());
    
            mDefaultTrafficStatsTag = findDefaultTrafficStatsTag(url);
        }

    在Request中有两个抽象方法须要子类去实现。

    /**
         * Subclasses must implement this to parse the raw network response
         * and return an appropriate response type. This method will be
         * called from a worker thread.  The response will not be delivered
         * if you return null.
         * @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);
    
        
    
        /**
         * Subclasses must implement this to perform delivery of the parsed
         * response to their listeners.  The given response is guaranteed to
         * be non-null; responses that fail to parse are not delivered.
         * @param response The parsed response returned by
         * {@link #parseNetworkResponse(NetworkResponse)}
         */
        abstract protected void deliverResponse(T response);

    一个是 parseNetworkResponse。就是说对于返回的数据。须要怎么去解析。解析成什么类型的数据。一个详细的请求。应该知道自己想要什么结果。比方StringRequest就是将结果解析成String。而ImageRequest则是将结果解析成Bitmap。这里作为抽象方法留给详细的子类实现;

    还有一个是 deliverResponse。用于解析完毕后将结果传递出去。这里传入的是解析好的数据类型,通常会在里面通过listener将结果传递到应用的场景下。如StringRequest,

        @Override
        protected void deliverResponse(String response) {
            mListener.onResponse(response);
        }

    3、NetworkResponse

    网络请求通用返回结果。数据存储在data中

        public NetworkResponse(int statusCode, byte[] data, Map<String, String> headers,
                boolean notModified) {
            this.statusCode = statusCode;
            this.data = data;
            this.headers = headers;
            this.notModified = notModified;
        }


    4、Response<T>

    响应结果的封装。包括终于结果result。缓存结构cacheEntry。出错信息error

    private Response(T result, Cache.Entry cacheEntry) {
            this.result = result;
            this.cacheEntry = cacheEntry;
            this.error = null;
        }

    二、运行过程

    有了上面的基本数据结构,之后就是考虑怎么去操作这些结构。完毕从请求到响应的整个过程。

    这里是整个Volley最核心的部分。也是体现作者设计思想的部分。涉及到任务调度、异步处理等。

    1、RequestQueue

    请求队列。全部请求都会通过RequestQueue的add方法增加到内部的队列里来等待处理,当请求结束得到响应结果后会调用finish方法将请求移出请求队列。

    RequestQueue中包括下面成员:

    • Cache 缓存结构,用于缓存响应结果;
    • Network 网络操作的实现
    • NetworkDispatcher 网络任务调度器
    • CacheDispatcher 缓存任务调度器
    • ResponseDelivery 响应投递,用于将结果从工作线程转移到UI线程
    • cacheQueue 缓存任务队列
    • networkQueue 网络任务队列

    RequestQueue完毕两项工作:

    启动、停止调度器:

    /**
         * Starts the dispatchers in this queue.
         */
        public void start() {
            stop();  // Make sure any currently running dispatchers are stopped.
            // Create the cache dispatcher and start it.
            mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery);
            mCacheDispatcher.start();
    
            // Create network dispatchers (and corresponding threads) up to the pool size.
            for (int i = 0; i < mDispatchers.length; i++) {
                NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork,
                        mCache, mDelivery);
                mDispatchers[i] = networkDispatcher;
                networkDispatcher.start();
            }
        }
    
        /**
         * Stops the cache and network dispatchers.
         */
        public void stop() {
            if (mCacheDispatcher != null) {
                mCacheDispatcher.quit();
            }
            for (int i = 0; i < mDispatchers.length; i++) {
                if (mDispatchers[i] != null) {
                    mDispatchers[i].quit();
                }
            }
        }

    将请求加入到对应的队列中,之后各个调度器会自行取出处理

        public <T> Request<T> add(Request<T> request) {
            // Tag the request as belonging to this queue and add it to the set of current requests.
            request.setRequestQueue(this);
            synchronized (mCurrentRequests) {
                mCurrentRequests.add(request);
            }
    
            // Process requests in the order they are added.
            request.setSequence(getSequenceNumber());
            request.addMarker("add-to-queue");
    
            // If the request is uncacheable, skip the cache queue and go straight to the network.
            if (!request.shouldCache()) {
                mNetworkQueue.add(request);
                return request;
            }
    
            // Insert request into stage if there's already a request with the same cache key in flight.
            synchronized (mWaitingRequests) {
                String cacheKey = request.getCacheKey();
                if (mWaitingRequests.containsKey(cacheKey)) {
                    // There is already a request in flight. Queue up.
                    Queue<Request<?>> stagedRequests = mWaitingRequests.get(cacheKey);
                    if (stagedRequests == null) {
                        stagedRequests = new LinkedList<Request<?>>();
                    }
                    stagedRequests.add(request);
                    mWaitingRequests.put(cacheKey, stagedRequests);
                    if (VolleyLog.DEBUG) {
                        VolleyLog.v("Request for cacheKey=%s is in flight, putting on hold.", cacheKey);
                    }
                } else {
                    // Insert 'null' queue for this cacheKey, indicating there is now a request in
                    // flight.
                    mWaitingRequests.put(cacheKey, null);
                    mCacheQueue.add(request);
                }
                return request;
            }
        }

    从上面能够看出,一个请求不要求缓存的话会被直接加到networkQueue中。否则会加到cacheQueue中。

    那调度器是怎么自行取出来并进行处理呢?

    2、CacheDispatcher,NetworkDispatcher

    调度器是线程,队列堵塞。有请求就运行。没有就等待。

    对缓存调度器CacheDispatcher,假设在缓存中没有找到响应结果。就会将请求加入到网络调度器NetworkDispatcher中

    while (true) {
                try {
                    // Get a request from the cache triage queue, blocking until
                    // at least one is available.
                    final Request<?

    > request = mCacheQueue.take(); request.addMarker("cache-queue-take"); // If the request has been canceled, don't bother dispatching it. if (request.isCanceled()) { request.finish("cache-discard-canceled"); continue; } // Attempt to retrieve this item from cache. Cache.Entry entry = mCache.get(request.getCacheKey()); if (entry == null) { request.addMarker("cache-miss"); // Cache miss; send off to the network dispatcher. mNetworkQueue.put(request); continue; } // If it is completely expired, just send it to the network. if (entry.isExpired()) { request.addMarker("cache-hit-expired"); request.setCacheEntry(entry); mNetworkQueue.put(request); continue; } // We have a cache hit; parse its data for delivery back to the request. 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. } } }); }


    NetworkDispatcher则是负责运行网络操作获取响应,调用Request解析响应从而得到指定的返回数据类型,将结果增加缓存。使用delivery将结果返回到UI线程。


  • 相关阅读:
    hdu 1395 2^x(mod n) = 1(C++)(欧拉定理 分解素因数)
    6. 数论准备知识
    hdu 2973 YAPTCHA(C++)(威尔逊定理)
    牛客小白月赛12——B.华华教月月做数学
    牛客小白月赛12——A.华华听月月唱歌
    5. 卡特兰数(Catalan)公式、证明、代码、典例.
    4.质数判定和质数筛法(埃拉托色尼筛选法,线性筛法/欧拉筛法)
    3.牛顿迭代法求解方程的根
    Codeforces刷题
    刷题计划
  • 原文地址:https://www.cnblogs.com/lytwajue/p/6844003.html
Copyright © 2011-2022 走看看