Home | History | Annotate | Download | only in volley
      1 /*
      2  * Copyright (C) 2011 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.volley;
     18 
     19 import android.net.TrafficStats;
     20 import android.os.Build;
     21 import android.os.Process;
     22 
     23 import java.util.concurrent.BlockingQueue;
     24 
     25 /**
     26  * Provides a thread for performing network dispatch from a queue of requests.
     27  *
     28  * Requests added to the specified queue are processed from the network via a
     29  * specified {@link Network} interface. Responses are committed to cache, if
     30  * eligible, using a specified {@link Cache} interface. Valid responses and
     31  * errors are posted back to the caller via a {@link ResponseDelivery}.
     32  */
     33 @SuppressWarnings("rawtypes")
     34 public class NetworkDispatcher extends Thread {
     35     /** The queue of requests to service. */
     36     private final BlockingQueue<Request> mQueue;
     37     /** The network interface for processing requests. */
     38     private final Network mNetwork;
     39     /** The cache to write to. */
     40     private final Cache mCache;
     41     /** For posting responses and errors. */
     42     private final ResponseDelivery mDelivery;
     43     /** Used for telling us to die. */
     44     private volatile boolean mQuit = false;
     45 
     46     /**
     47      * Creates a new network dispatcher thread.  You must call {@link #start()}
     48      * in order to begin processing.
     49      *
     50      * @param queue Queue of incoming requests for triage
     51      * @param network Network interface to use for performing requests
     52      * @param cache Cache interface to use for writing responses to cache
     53      * @param delivery Delivery interface to use for posting responses
     54      */
     55     public NetworkDispatcher(BlockingQueue<Request> queue,
     56             Network network, Cache cache,
     57             ResponseDelivery delivery) {
     58         mQueue = queue;
     59         mNetwork = network;
     60         mCache = cache;
     61         mDelivery = delivery;
     62     }
     63 
     64     /**
     65      * Forces this dispatcher to quit immediately.  If any requests are still in
     66      * the queue, they are not guaranteed to be processed.
     67      */
     68     public void quit() {
     69         mQuit = true;
     70         interrupt();
     71     }
     72 
     73     @Override
     74     public void run() {
     75         Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
     76         Request request;
     77         while (true) {
     78             try {
     79                 // Take a request from the queue.
     80                 request = mQueue.take();
     81             } catch (InterruptedException e) {
     82                 // We may have been interrupted because it was time to quit.
     83                 if (mQuit) {
     84                     return;
     85                 }
     86                 continue;
     87             }
     88 
     89             try {
     90                 request.addMarker("network-queue-take");
     91 
     92                 // If the request was cancelled already, do not perform the
     93                 // network request.
     94                 if (request.isCanceled()) {
     95                     request.finish("network-discard-cancelled");
     96                     continue;
     97                 }
     98 
     99                 // Tag the request (if API >= 14)
    100                 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
    101                     TrafficStats.setThreadStatsTag(request.getTrafficStatsTag());
    102                 }
    103 
    104                 // Perform the network request.
    105                 NetworkResponse networkResponse = mNetwork.performRequest(request);
    106                 request.addMarker("network-http-complete");
    107 
    108                 // If the server returned 304 AND we delivered a response already,
    109                 // we're done -- don't deliver a second identical response.
    110                 if (networkResponse.notModified && request.hasHadResponseDelivered()) {
    111                     request.finish("not-modified");
    112                     continue;
    113                 }
    114 
    115                 // Parse the response here on the worker thread.
    116                 Response<?> response = request.parseNetworkResponse(networkResponse);
    117                 request.addMarker("network-parse-complete");
    118 
    119                 // Write to cache if applicable.
    120                 // TODO: Only update cache metadata instead of entire record for 304s.
    121                 if (request.shouldCache() && response.cacheEntry != null) {
    122                     mCache.put(request.getCacheKey(), response.cacheEntry);
    123                     request.addMarker("network-cache-written");
    124                 }
    125 
    126                 // Post the response back.
    127                 request.markDelivered();
    128                 mDelivery.postResponse(request, response);
    129             } catch (VolleyError volleyError) {
    130                 parseAndDeliverNetworkError(request, volleyError);
    131             } catch (Exception e) {
    132                 VolleyLog.e(e, "Unhandled exception %s", e.toString());
    133                 mDelivery.postError(request, new VolleyError(e));
    134             }
    135         }
    136     }
    137 
    138     private void parseAndDeliverNetworkError(Request<?> request, VolleyError error) {
    139         error = request.parseNetworkError(error);
    140         mDelivery.postError(request, error);
    141     }
    142 }
    143