zoukankan      html  css  js  c++  java
  • Volley学习(RequestQueue分析)

          Volley的RequestQueue用来缓存请求处理器CacheDispatch和网络请求处理器NetworkDispatch来处理Request的。当我们调用RequestQueue.start()是,两个处理器开始运行起来,等待Request的到来。

           

     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();
            }
        }
    

      Volley先读缓存然后,没有cache hit的话再从网络上获取,所以先启动CacheDispatcher,然后启动NetworkDispatcher。不过在启动处理器前先调用stop()函数清除掉以前RequestQueue里的过期的Dispatcher(Dispatcher都是继承Thread)。以防影响性能。Volley启动一个CacheDispatcher和4个NetworkDispatcher,之所以这样设计,个人人为是主要考虑到网络图片的下载,所以利用多个NetworkDispatcher来处理网络请求。然后看一下stop()函数。

       

       public void stop() {
            if (mCacheDispatcher != null) {
                mCacheDispatcher.quit();
            }
            for (int i = 0; i < mDispatchers.length; i++) {
                if (mDispatchers[i] != null) {
                    mDispatchers[i].quit();
                }
            }
        }
    

       调用Dispatcher的quit()函数来结束线程。以NetworkDispatcher.quit()为例:

     public void quit() {
            mQuit = true;
            interrupt();
        }
    

      函数将mQuit变量置为true。为什么要这样做,因为在networkdispatcher线程中的中断异常处理中,判断mQuit的值,如果真,则退出循环,结束线程。否则continue,继续从Queue中去取Request处理。

     try {
                    // Take a request from the queue.
                    request = mQueue.take();
                } catch (InterruptedException e) {
                    // We may have been interrupted because it was time to quit.
                    if (mQuit) {
                        return;
                    }
                    continue;
                }
    

      接下来,看下RequestQueue的add函数。

       

     public Request add(Request 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;
            }
        }
    

      首先将Request加入到mCurrentRequests中,因为存在多个线程竞争的问题,在这个代码块上进行了同步。然后request.setSequence().为当前Request分配一个序列号,为什么这样做,因为我们下面要将Request放到NetworkQueue中或者CacheQueue中,这两个队列都是PriorityBlockingQueue,里面的元素是根据自定义的权重来排序的。PriorityBlockingQueue里的元素须实现Comparable接口,来看下我们这里的Requeset的实现:

        

     @Override
        public int compareTo(Request<T> other) {
            Priority left = this.getPriority();
            Priority right = other.getPriority();
    
            // High-priority requests are "lesser" so they are sorted to the front.
            // Equal priorities are sorted by sequence number to provide FIFO ordering.
            return left == right ?
                    this.mSequence - other.mSequence :
                    right.ordinal() - left.ordinal();
        }
    

      Request的策略是现根据每个Request的Priority来判断,如果两个Request的Priority相同,那么载根据两个Request的Sequence来进行判断队列里的先后顺序。

         

    1 public enum Priority {
    2         LOW,
    3         NORMAL,
    4         HIGH,
    5         IMMEDIATE
    6     }
    View Code

      

         给当前Request加上序列后,判断一下当前Request是否需要缓存,如果不需要则直接把Request加入到NetworkQueue队列里。如果需要缓存,取出Request的缓存键,从mWaitingRequests里看下有没有Request的缓存键.在RequestQueue中有四个队列。mCurrentRequests,mWaitingRequests,mCacheQueue,mNetworkQueue。每当一个请求到来时,先加入到mCurrentRequests,然后判断当前Request是否需要缓存,如果不用缓存的Request,则直接加入到mNetworkQueue队列中等待网络处理器(NetWorkDispatcher)去处理。如果需要缓存的话,根据Request获取相应的cacheKey,如果cacheKey不存在的话,说明这个需要缓存的Request是第一次请求。那么将cacheKey放入到mWaitingRequests队列里。(这里插播一下,mCurrentRequests存放的是所有交由RequestQueue处理的Request,mWaitingRequests里存放的是mCacheQueue里已经有相同url的Request,mWatiingRequests的出现就是为了避免不必要的网络数据获取),并将Request放入到mCacheQueue中以做处理。

    1   // Insert 'null' queue for this cacheKey, indicating there is now a request in
    2                 // flight.
    3                 mWaitingRequests.put(cacheKey, null);
    4                 mCacheQueue.add(request);
    View Code

        如果cacheKey存在的话,说明已经有相同的Request正在处理(这里的cacheKey是通过getUrl()得到的,也就是创建Request时的url)。这时将此Request放入到mWaitingRequest队列中等待In-flight Request的处理结果。

        add完然后看finish(Request req);

     1  void finish(Request request) {
     2         // Remove from the set of requests currently being processed.
     3         synchronized (mCurrentRequests) {
     4             mCurrentRequests.remove(request);
     5         }
     6 
     7         if (request.shouldCache()) {
     8             synchronized (mWaitingRequests) {
     9                 String cacheKey = request.getCacheKey();
    10                 Queue<Request> waitingRequests = mWaitingRequests.remove(cacheKey);
    11                 if (waitingRequests != null) {
    12                     if (VolleyLog.DEBUG) {
    13                         VolleyLog.v("Releasing %d waiting requests for cacheKey=%s.",
    14                                 waitingRequests.size(), cacheKey);
    15                     }
    16                     // Process all queued up requests. They won't be considered as in flight, but
    17                     // that's not a problem as the cache has been primed by 'request'.
    18                     mCacheQueue.addAll(waitingRequests);
    19                 }
    20             }
    21         }
    22     }
    View Code

         首先先从mCurrentRequests集合中remove掉当前Request,然后在mWaitingRequests中去掉当前的Request.然后将此Request对应的mWaitingRequest中存储的Request放到mCacheQueue中等待处理(因为此时对应的url的网络数据已经加载到本地,所以这些mWaitingRequests里的Request被处理时直接从本地解析,不用耗时的网络获取一遍)。

        RequestQueue类中还有一个CancelAll()函数,它的作用是根据指定的Request tag来删除响应的Request.

        public void cancelAll(RequestFilter filter) {
            synchronized (mCurrentRequests) {
                for (Request<?> request : mCurrentRequests) {
                    if (filter.apply(request)) {
                        request.cancel();
                    }
                }
            }
        }
    
        /**
         * Cancels all requests in this queue with the given tag. Tag must be non-null
         * and equality is by identity.
         */
        public void cancelAll(final Object tag) {
            if (tag == null) {
                throw new IllegalArgumentException("Cannot cancelAll with a null tag");
            }
            cancelAll(new RequestFilter() {
                @Override
                public boolean apply(Request<?> request) {
                    return request.getTag() == tag;
                }
            });
        }
    

      

  • 相关阅读:
    maven安装
    删掉centos原有的openjdk并安装sun jdk
    搭建私有仓库Harbor
    什么是Docker
    总结docker常用命令
    MySQL如何修改密码
    VMware vSphere
    安装Esxi 6.5
    Linux安装python3.6
    提高Linux运维效率的30个命令行常用快捷键
  • 原文地址:https://www.cnblogs.com/mKaoree/p/4471312.html
Copyright © 2011-2022 走看看