aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/com/android
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/com/android')
-rw-r--r--src/main/java/com/android/volley/CacheDispatcher.java123
-rw-r--r--src/main/java/com/android/volley/NetworkDispatcher.java3
-rw-r--r--src/main/java/com/android/volley/Request.java6
-rw-r--r--src/main/java/com/android/volley/RequestQueue.java75
4 files changed, 148 insertions, 59 deletions
diff --git a/src/main/java/com/android/volley/CacheDispatcher.java b/src/main/java/com/android/volley/CacheDispatcher.java
index f616285..13f250b 100644
--- a/src/main/java/com/android/volley/CacheDispatcher.java
+++ b/src/main/java/com/android/volley/CacheDispatcher.java
@@ -122,75 +122,80 @@ public class CacheDispatcher extends Thread {
@VisibleForTesting
void processRequest(final Request<?> request) throws InterruptedException {
request.addMarker("cache-queue-take");
+ request.sendEvent(RequestQueue.RequestEvent.REQUEST_CACHE_LOOKUP_STARTED);
- // If the request has been canceled, don't bother dispatching it.
- if (request.isCanceled()) {
- request.finish("cache-discard-canceled");
- return;
- }
+ try {
+ // If the request has been canceled, don't bother dispatching it.
+ if (request.isCanceled()) {
+ request.finish("cache-discard-canceled");
+ return;
+ }
- // Attempt to retrieve this item from cache.
- Cache.Entry entry = mCache.get(request.getCacheKey());
- if (entry == null) {
- request.addMarker("cache-miss");
- // Cache miss; send off to the network dispatcher.
- if (!mWaitingRequestManager.maybeAddToWaitingRequests(request)) {
- mNetworkQueue.put(request);
+ // Attempt to retrieve this item from cache.
+ Cache.Entry entry = mCache.get(request.getCacheKey());
+ if (entry == null) {
+ request.addMarker("cache-miss");
+ // Cache miss; send off to the network dispatcher.
+ if (!mWaitingRequestManager.maybeAddToWaitingRequests(request)) {
+ mNetworkQueue.put(request);
+ }
+ return;
}
- return;
- }
- // If it is completely expired, just send it to the network.
- if (entry.isExpired()) {
- request.addMarker("cache-hit-expired");
- request.setCacheEntry(entry);
- if (!mWaitingRequestManager.maybeAddToWaitingRequests(request)) {
- mNetworkQueue.put(request);
+ // If it is completely expired, just send it to the network.
+ if (entry.isExpired()) {
+ request.addMarker("cache-hit-expired");
+ request.setCacheEntry(entry);
+ if (!mWaitingRequestManager.maybeAddToWaitingRequests(request)) {
+ mNetworkQueue.put(request);
+ }
+ return;
}
- return;
- }
- // We have a cache hit; parse its data for delivery back to the request.
- request.addMarker("cache-hit");
- Response<?> response =
- request.parseNetworkResponse(
- new NetworkResponse(entry.data, entry.responseHeaders));
- request.addMarker("cache-hit-parsed");
+ // We have a cache hit; parse its data for delivery back to the request.
+ request.addMarker("cache-hit");
+ Response<?> response =
+ request.parseNetworkResponse(
+ new NetworkResponse(entry.data, entry.responseHeaders));
+ request.addMarker("cache-hit-parsed");
- if (!entry.refreshNeeded()) {
- // Completely unexpired cache hit. Just deliver the response.
- mDelivery.postResponse(request, response);
- } else {
- // Soft-expired cache hit. We can deliver the cached response,
- // but we need to also send the request to the network for
- // refreshing.
- request.addMarker("cache-hit-refresh-needed");
- request.setCacheEntry(entry);
- // Mark the response as intermediate.
- response.intermediate = true;
+ if (!entry.refreshNeeded()) {
+ // Completely unexpired cache hit. Just deliver the response.
+ mDelivery.postResponse(request, response);
+ } else {
+ // Soft-expired cache hit. We can deliver the cached response,
+ // but we need to also send the request to the network for
+ // refreshing.
+ request.addMarker("cache-hit-refresh-needed");
+ request.setCacheEntry(entry);
+ // Mark the response as intermediate.
+ response.intermediate = true;
- if (!mWaitingRequestManager.maybeAddToWaitingRequests(request)) {
- // Post the intermediate response back to the user and have
- // the delivery then forward the request along to the network.
- mDelivery.postResponse(
- request,
- response,
- new Runnable() {
- @Override
- public void run() {
- try {
- mNetworkQueue.put(request);
- } catch (InterruptedException e) {
- // Restore the interrupted status
- Thread.currentThread().interrupt();
+ if (!mWaitingRequestManager.maybeAddToWaitingRequests(request)) {
+ // Post the intermediate response back to the user and have
+ // the delivery then forward the request along to the network.
+ mDelivery.postResponse(
+ request,
+ response,
+ new Runnable() {
+ @Override
+ public void run() {
+ try {
+ mNetworkQueue.put(request);
+ } catch (InterruptedException e) {
+ // Restore the interrupted status
+ Thread.currentThread().interrupt();
+ }
}
- }
- });
- } else {
- // request has been added to list of waiting requests
- // to receive the network response from the first request once it returns.
- mDelivery.postResponse(request, response);
+ });
+ } else {
+ // request has been added to list of waiting requests
+ // to receive the network response from the first request once it returns.
+ mDelivery.postResponse(request, response);
+ }
}
+ } finally {
+ request.sendEvent(RequestQueue.RequestEvent.REQUEST_CACHE_LOOKUP_FINISHED);
}
}
diff --git a/src/main/java/com/android/volley/NetworkDispatcher.java b/src/main/java/com/android/volley/NetworkDispatcher.java
index 327afed..762e030 100644
--- a/src/main/java/com/android/volley/NetworkDispatcher.java
+++ b/src/main/java/com/android/volley/NetworkDispatcher.java
@@ -114,6 +114,7 @@ public class NetworkDispatcher extends Thread {
@VisibleForTesting
void processRequest(Request<?> request) {
long startTimeMs = SystemClock.elapsedRealtime();
+ request.sendEvent(RequestQueue.RequestEvent.REQUEST_NETWORK_DISPATCH_STARTED);
try {
request.addMarker("network-queue-take");
@@ -164,6 +165,8 @@ public class NetworkDispatcher extends Thread {
volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs);
mDelivery.postError(request, volleyError);
request.notifyListenerResponseNotUsable();
+ } finally {
+ request.sendEvent(RequestQueue.RequestEvent.REQUEST_NETWORK_DISPATCH_FINISHED);
}
}
diff --git a/src/main/java/com/android/volley/Request.java b/src/main/java/com/android/volley/Request.java
index cd7290a..0b18abb 100644
--- a/src/main/java/com/android/volley/Request.java
+++ b/src/main/java/com/android/volley/Request.java
@@ -251,6 +251,12 @@ public abstract class Request<T> implements Comparable<Request<T>> {
}
}
+ void sendEvent(@RequestQueue.RequestEvent int event) {
+ if (mRequestQueue != null) {
+ mRequestQueue.sendRequestEvent(this, event);
+ }
+ }
+
/**
* Associates this request with the given queue. The request queue will be notified when this
* request has finished.
diff --git a/src/main/java/com/android/volley/RequestQueue.java b/src/main/java/com/android/volley/RequestQueue.java
index a9312be..42b3fa2 100644
--- a/src/main/java/com/android/volley/RequestQueue.java
+++ b/src/main/java/com/android/volley/RequestQueue.java
@@ -18,6 +18,9 @@ package com.android.volley;
import android.os.Handler;
import android.os.Looper;
+import android.support.annotation.IntDef;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
@@ -38,11 +41,53 @@ public class RequestQueue {
// TODO: This should not be a generic class, because the request type can't be determined at
// compile time, so all calls to onRequestFinished are unsafe. However, changing this would be
// an API-breaking change. See also: https://github.com/google/volley/pull/109
+ @Deprecated // Use RequestEventListener instead.
public interface RequestFinishedListener<T> {
/** Called when a request has finished processing. */
void onRequestFinished(Request<T> request);
}
+ /** Request event types the listeners {@link RequestEventListener} will be notified about. */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({
+ RequestEvent.REQUEST_QUEUED,
+ RequestEvent.REQUEST_CACHE_LOOKUP_STARTED,
+ RequestEvent.REQUEST_CACHE_LOOKUP_FINISHED,
+ RequestEvent.REQUEST_NETWORK_DISPATCH_STARTED,
+ RequestEvent.REQUEST_NETWORK_DISPATCH_FINISHED,
+ RequestEvent.REQUEST_FINISHED
+ })
+ public @interface RequestEvent {
+ /** The request was added to the queue. */
+ public static final int REQUEST_QUEUED = 0;
+ /** Cache lookup started for the request. */
+ public static final int REQUEST_CACHE_LOOKUP_STARTED = 1;
+ /**
+ * Cache lookup finished for the request and cached response is delivered or request is
+ * queued for network dispatching.
+ */
+ public static final int REQUEST_CACHE_LOOKUP_FINISHED = 2;
+ /** Network dispatch started for the request. */
+ public static final int REQUEST_NETWORK_DISPATCH_STARTED = 3;
+ /** The network dispatch finished for the request and response (if any) is delivered. */
+ public static final int REQUEST_NETWORK_DISPATCH_FINISHED = 4;
+ /**
+ * All the work associated with the request is finished and request is removed from all the
+ * queues.
+ */
+ public static final int REQUEST_FINISHED = 5;
+ }
+
+ /** Callback interface for request life cycle events. */
+ public interface RequestEventListener {
+ /**
+ * Called on every request lifecycle event. Can be called from different threads. The call
+ * is blocking request processing, so any processing should be kept at minimum or moved to
+ * another thread.
+ */
+ void onRequestEvent(Request<?> request, @RequestEvent int event);
+ }
+
/** Used for generating monotonically-increasing sequence numbers for requests. */
private final AtomicInteger mSequenceGenerator = new AtomicInteger();
@@ -78,6 +123,9 @@ public class RequestQueue {
private final List<RequestFinishedListener> mFinishedListeners = new ArrayList<>();
+ /** Collection of listeners for request life cycle events. */
+ private final List<RequestEventListener> mEventListeners = new ArrayList<>();
+
/**
* Creates the worker pool. Processing will not begin until {@link #start()} is called.
*
@@ -213,6 +261,7 @@ public class RequestQueue {
// Process requests in the order they are added.
request.setSequence(getSequenceNumber());
request.addMarker("add-to-queue");
+ sendRequestEvent(request, RequestEvent.REQUEST_QUEUED);
// If the request is uncacheable, skip the cache queue and go straight to the network.
if (!request.shouldCache()) {
@@ -238,8 +287,33 @@ public class RequestQueue {
listener.onRequestFinished(request);
}
}
+ sendRequestEvent(request, RequestEvent.REQUEST_FINISHED);
+ }
+
+ /** Sends a request life cycle event to the listeners. */
+ void sendRequestEvent(Request<?> request, @RequestEvent int event) {
+ synchronized (mEventListeners) {
+ for (RequestEventListener listener : mEventListeners) {
+ listener.onRequestEvent(request, event);
+ }
+ }
+ }
+
+ /** Add a listener for request life cycle events. */
+ public void addRequestEventListener(RequestEventListener listener) {
+ synchronized (mEventListeners) {
+ mEventListeners.add(listener);
+ }
+ }
+
+ /** Remove a listener for request life cycle events. */
+ public void removeRequestEventListener(RequestEventListener listener) {
+ synchronized (mEventListeners) {
+ mEventListeners.remove(listener);
+ }
}
+ @Deprecated // Use RequestEventListener instead.
public <T> void addRequestFinishedListener(RequestFinishedListener<T> listener) {
synchronized (mFinishedListeners) {
mFinishedListeners.add(listener);
@@ -247,6 +321,7 @@ public class RequestQueue {
}
/** Remove a RequestFinishedListener. Has no effect if listener was not previously added. */
+ @Deprecated // Use RequestEventListener instead.
public <T> void removeRequestFinishedListener(RequestFinishedListener<T> listener) {
synchronized (mFinishedListeners) {
mFinishedListeners.remove(listener);