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 17package com.android.volley; 18 19import java.util.concurrent.BlockingQueue; 20 21/** 22 * Provides a thread for performing network dispatch from a queue of requests. 23 * 24 * Requests added to the specified queue are processed from the network via a 25 * specified {@link Network} interface. Responses are committed to cache, if 26 * eligible, using a specified {@link Cache} interface. Valid responses and 27 * errors are posted back to the caller via a {@link ResponseDelivery}. 28 */ 29@SuppressWarnings("rawtypes") 30public class NetworkDispatcher extends Thread { 31 /** The queue of requests to service. */ 32 private final BlockingQueue<Request> mQueue; 33 /** The network interface for processing requests. */ 34 private final Network mNetwork; 35 /** The cache to write to. */ 36 private final Cache mCache; 37 /** For posting responses and errors. */ 38 private final ResponseDelivery mDelivery; 39 /** Used for telling us to die. */ 40 private volatile boolean mQuit = false; 41 42 /** 43 * Creates a new network dispatcher thread. You must call {@link #start()} 44 * in order to begin processing. 45 * 46 * @param queue Queue of incoming requests for triage 47 * @param network Network interface to use for performing requests 48 * @param cache Cache interface to use for writing responses to cache 49 * @param delivery Delivery interface to use for posting responses 50 */ 51 public NetworkDispatcher(BlockingQueue<Request> queue, 52 Network network, Cache cache, 53 ResponseDelivery delivery) { 54 mQueue = queue; 55 mNetwork = network; 56 mCache = cache; 57 mDelivery = delivery; 58 } 59 60 /** 61 * Forces this dispatcher to quit immediately. If any requests are still in 62 * the queue, they are not guaranteed to be processed. 63 */ 64 public void quit() { 65 mQuit = true; 66 interrupt(); 67 } 68 69 @Override 70 public void run() { 71 Request request; 72 while (true) { 73 try { 74 // Take a request from the queue. 75 request = mQueue.take(); 76 } catch (InterruptedException e) { 77 // We may have been interrupted because it was time to quit. 78 if (mQuit) { 79 return; 80 } 81 continue; 82 } 83 84 try { 85 request.addMarker("network-queue-take"); 86 87 // If the request was cancelled already, do not perform the 88 // network request. 89 if (request.isCanceled()) { 90 request.finish("network-discard-cancelled"); 91 continue; 92 } 93 94 // Perform the network request. 95 NetworkResponse networkResponse = mNetwork.performRequest(request); 96 request.addMarker("network-http-complete"); 97 98 // If the server returned 304 AND we delivered a response already, 99 // we're done -- don't deliver a second identical response. 100 if (networkResponse.notModified && request.hasHadResponseDelivered()) { 101 request.finish("not-modified"); 102 continue; 103 } 104 105 // Parse the response here on the worker thread. 106 Response<?> response = request.parseNetworkResponse(networkResponse); 107 request.addMarker("network-parse-complete"); 108 109 // Write to cache if applicable. 110 // TODO: Only update cache metadata instead of entire record for 304s. 111 if (request.shouldCache() && response.cacheEntry != null) { 112 mCache.put(request.getCacheKey(), response.cacheEntry); 113 request.addMarker("network-cache-written"); 114 } 115 116 // Post the response back. 117 request.markDelivered(); 118 mDelivery.postResponse(request, response); 119 } catch (VolleyError volleyError) { 120 parseAndDeliverNetworkError(request, volleyError); 121 } catch (Exception e) { 122 VolleyLog.e("Unhandled exception %s", e.toString()); 123 mDelivery.postError(request, new VolleyError(e)); 124 } 125 } 126 } 127 128 private void parseAndDeliverNetworkError(Request<?> request, VolleyError error) { 129 error = request.parseNetworkError(error); 130 mDelivery.postError(request, error); 131 } 132} 133