Example #1
0
  /**
   * Called from {@link Request#finish(String)}, indicating that processing of the given request has
   * finished.
   *
   * <p>Releases waiting requests for <code>request.getCacheKey()</code> if <code>
   * request.shouldCache()</code>.
   *
   * <p>(1). 首先从正在进行中请求集合mCurrentRequests中移除该请求。 (2).
   * 然后查找请求等待集合mWaitingRequests中是否存在等待的请求,如果存在,则将等待队列移除,
   * 并将等待队列所有的请求添加到缓存请求队列中,让缓存请求处理线程CacheDispatcher自动处理。
   */
  <T> void finish(Request<T> request) {
    // Remove from the set of requests currently being processed.
    synchronized (mCurrentRequests) {
      mCurrentRequests.remove(request);
    }
    synchronized (mFinishedListeners) {
      for (RequestFinishedListener<T> listener : mFinishedListeners) {
        listener.onRequestFinished(request);
      }
    }

    if (request.shouldCache()) {
      synchronized (mWaitingRequests) {
        String cacheKey = request.getCacheKey();
        Queue<Request<?>> waitingRequests = mWaitingRequests.remove(cacheKey);
        if (waitingRequests != null) {
          if (VolleyLog.DEBUG) {
            VolleyLog.v(
                "Releasing %d waiting requests for cacheKey=%s.", waitingRequests.size(), cacheKey);
          }
          // Process all queued up requests. They won't be considered as in flight, but
          // that's not a problem as the cache has been primed by 'request'.
          mCacheQueue.addAll(waitingRequests);
        }
      }
    }
  }
  /**
   * Adds a Request to the dispatch queue.
   *
   * @param request The request to service
   * @return The passed-in request
   */
  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);

    // Rewrite the url, in case of GET requests
    if (mUrlRewriter != null) {
      request.setUrl(mUrlRewriter.rewriteUrl(request));
    }

    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.sDebug) {
          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;
    }
  }
  @Override
  public void run() {
    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
    Request request;
    while (true) {
      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;
      }

      try {
        request.addMarker("network-queue-take");

        // If the request was cancelled already, do not perform the
        // network request.
        if (request.isCanceled()) {
          request.finish("network-discard-cancelled");
          continue;
        }

        // Tag the request (if API >= 14)
        if (Build.VERSION.SDK_INT >= 14) {
          TrafficStats.setThreadStatsTag(request.getTrafficStatsTag());
        }

        // Perform the network request.
        NetworkResponse networkResponse = mNetwork.performRequest(request);
        request.addMarker("network-http-complete");

        // If the server returned 304 AND we delivered a response already,
        // we're done -- don't deliver a second identical response.
        if (networkResponse.notModified && request.hasHadResponseDelivered()) {
          request.finish("not-modified");
          continue;
        }

        // Parse the response here on the worker thread.
        Response<?> response = request.parseNetworkResponse(networkResponse);
        request.addMarker("network-parse-complete");

        // Write to cache if applicable.
        // TODO: Only update cache metadata instead of entire record for 304s.
        if (request.shouldCache() && response.cacheEntry != null) {
          mCache.put(request.getCacheKey(), response.cacheEntry);
          request.addMarker("network-cache-written");
        }

        // Post the response back.
        request.markDelivered();
        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));
      }
    }
  }