blob: a654ead5be6cfb4b48f0ec40b12599127c03d808 [file] [log] [blame]
Jean-Baptiste Querud56b88a2012-11-07 07:48:57 -08001/*
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
Ficus Kirkpatrick35d5cc32014-02-08 11:15:04 -080019import android.annotation.TargetApi;
Evan Charltoncc3a9342013-04-25 15:19:22 -070020import android.net.TrafficStats;
21import android.os.Build;
Jean-Baptiste Queru6772bce2012-11-07 07:51:33 -080022import android.os.Process;
23
Jean-Baptiste Querud56b88a2012-11-07 07:48:57 -080024import java.util.concurrent.BlockingQueue;
25
26/**
27 * Provides a thread for performing network dispatch from a queue of requests.
28 *
29 * Requests added to the specified queue are processed from the network via a
30 * specified {@link Network} interface. Responses are committed to cache, if
31 * eligible, using a specified {@link Cache} interface. Valid responses and
32 * errors are posted back to the caller via a {@link ResponseDelivery}.
33 */
Jean-Baptiste Querud56b88a2012-11-07 07:48:57 -080034public class NetworkDispatcher extends Thread {
35 /** The queue of requests to service. */
Ficus Kirkpatrick35d5cc32014-02-08 11:15:04 -080036 private final BlockingQueue<Request<?>> mQueue;
Jean-Baptiste Querud56b88a2012-11-07 07:48:57 -080037 /** 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 */
Ficus Kirkpatrick35d5cc32014-02-08 11:15:04 -080055 public NetworkDispatcher(BlockingQueue<Request<?>> queue,
Jean-Baptiste Querud56b88a2012-11-07 07:48:57 -080056 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
Ficus Kirkpatrick35d5cc32014-02-08 11:15:04 -080073 @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
74 private void addTrafficStatsTag(Request<?> request) {
75 // Tag the request (if API >= 14)
76 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
77 TrafficStats.setThreadStatsTag(request.getTrafficStatsTag());
78 }
79 }
80
Jean-Baptiste Querud56b88a2012-11-07 07:48:57 -080081 @Override
82 public void run() {
Jean-Baptiste Queru6772bce2012-11-07 07:51:33 -080083 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
Ficus Kirkpatrick35d5cc32014-02-08 11:15:04 -080084 Request<?> request;
Jean-Baptiste Querud56b88a2012-11-07 07:48:57 -080085 while (true) {
86 try {
87 // Take a request from the queue.
88 request = mQueue.take();
89 } catch (InterruptedException e) {
90 // We may have been interrupted because it was time to quit.
91 if (mQuit) {
92 return;
93 }
94 continue;
95 }
96
97 try {
98 request.addMarker("network-queue-take");
99
100 // If the request was cancelled already, do not perform the
101 // network request.
102 if (request.isCanceled()) {
103 request.finish("network-discard-cancelled");
104 continue;
105 }
106
Ficus Kirkpatrick35d5cc32014-02-08 11:15:04 -0800107 addTrafficStatsTag(request);
Evan Charltoncc3a9342013-04-25 15:19:22 -0700108
Jean-Baptiste Querud56b88a2012-11-07 07:48:57 -0800109 // Perform the network request.
110 NetworkResponse networkResponse = mNetwork.performRequest(request);
111 request.addMarker("network-http-complete");
112
113 // If the server returned 304 AND we delivered a response already,
114 // we're done -- don't deliver a second identical response.
115 if (networkResponse.notModified && request.hasHadResponseDelivered()) {
116 request.finish("not-modified");
117 continue;
118 }
119
120 // Parse the response here on the worker thread.
121 Response<?> response = request.parseNetworkResponse(networkResponse);
122 request.addMarker("network-parse-complete");
123
124 // Write to cache if applicable.
125 // TODO: Only update cache metadata instead of entire record for 304s.
126 if (request.shouldCache() && response.cacheEntry != null) {
127 mCache.put(request.getCacheKey(), response.cacheEntry);
128 request.addMarker("network-cache-written");
129 }
130
131 // Post the response back.
132 request.markDelivered();
133 mDelivery.postResponse(request, response);
134 } catch (VolleyError volleyError) {
135 parseAndDeliverNetworkError(request, volleyError);
136 } catch (Exception e) {
Evan Charltonc0d371c2012-11-16 15:58:05 -0800137 VolleyLog.e(e, "Unhandled exception %s", e.toString());
Jean-Baptiste Querud56b88a2012-11-07 07:48:57 -0800138 mDelivery.postError(request, new VolleyError(e));
139 }
140 }
141 }
142
143 private void parseAndDeliverNetworkError(Request<?> request, VolleyError error) {
144 error = request.parseNetworkError(error);
145 mDelivery.postError(request, error);
146 }
147}