Skip to content

Commit c21d17f

Browse files
committed
Merge pull request square#666 from lucasr/request-priority
Implement support for request priorities
2 parents 5bdb180 + dd3954c commit c21d17f

File tree

9 files changed

+297
-9
lines changed

9 files changed

+297
-9
lines changed

picasso/src/main/java/com/squareup/picasso/Action.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import android.graphics.Bitmap;
1919
import android.graphics.drawable.Drawable;
20+
import com.squareup.picasso.Picasso.Priority;
2021
import java.lang.ref.ReferenceQueue;
2122
import java.lang.ref.WeakReference;
2223

@@ -85,4 +86,8 @@ boolean willReplay() {
8586
Picasso getPicasso() {
8687
return picasso;
8788
}
89+
90+
Priority getPriority() {
91+
return request.priority;
92+
}
8893
}

picasso/src/main/java/com/squareup/picasso/BitmapHunter.java

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,11 @@
2424
import java.util.ArrayList;
2525
import java.util.List;
2626
import java.util.concurrent.Future;
27+
import java.util.concurrent.atomic.AtomicInteger;
2728

2829
import static com.squareup.picasso.Picasso.LoadedFrom.MEMORY;
30+
import static com.squareup.picasso.Picasso.Priority;
31+
import static com.squareup.picasso.Picasso.Priority.LOW;
2932
import static com.squareup.picasso.Utils.OWNER_HUNTER;
3033
import static com.squareup.picasso.Utils.VERB_DECODED;
3134
import static com.squareup.picasso.Utils.VERB_EXECUTING;
@@ -49,6 +52,9 @@ class BitmapHunter implements Runnable {
4952
}
5053
};
5154

55+
private static final AtomicInteger SEQUENCE_GENERATOR = new AtomicInteger();
56+
57+
final int sequence;
5258
final Picasso picasso;
5359
final Dispatcher dispatcher;
5460
final Cache cache;
@@ -66,9 +72,11 @@ class BitmapHunter implements Runnable {
6672
Exception exception;
6773
int exifRotation; // Determined during decoding of original resource.
6874
int retryCount;
75+
Priority priority;
6976

7077
BitmapHunter(Picasso picasso, Dispatcher dispatcher, Cache cache, Stats stats, Action action,
7178
RequestHandler requestHandler) {
79+
this.sequence = SEQUENCE_GENERATOR.incrementAndGet();
7280
this.picasso = picasso;
7381
this.dispatcher = dispatcher;
7482
this.cache = cache;
@@ -79,6 +87,7 @@ class BitmapHunter implements Runnable {
7987
this.requestHandler = requestHandler;
8088
this.retryCount = requestHandler.getRetryCount();
8189
this.action = action;
90+
this.priority = (action != null ? action.getPriority() : LOW);
8291
}
8392

8493
@Override public void run() {
@@ -192,20 +201,59 @@ void attach(Action action) {
192201
if (loggingEnabled) {
193202
log(OWNER_HUNTER, VERB_JOINED, request.logId(), getLogIdsForHunter(this, "to "));
194203
}
204+
205+
Priority actionPriority = action.getPriority();
206+
if (actionPriority.ordinal() > priority.ordinal()) {
207+
priority = actionPriority;
208+
}
195209
}
196210

197211
void detach(Action action) {
212+
boolean detached = false;
198213
if (this.action == action) {
199214
this.action = null;
215+
detached = true;
200216
} else if (actions != null) {
201-
actions.remove(action);
217+
detached = actions.remove(action);
218+
}
219+
220+
// The action being detached had the highest priority. Update this
221+
// hunter's priority with the remaining actions.
222+
if (detached && action.getPriority() == priority) {
223+
priority = computeNewPriority();
202224
}
203225

204226
if (picasso.loggingEnabled) {
205227
log(OWNER_HUNTER, VERB_REMOVED, action.request.logId(), getLogIdsForHunter(this, "from "));
206228
}
207229
}
208230

231+
private Priority computeNewPriority() {
232+
Priority newPriority = LOW;
233+
234+
boolean hasMultiple = actions != null && !actions.isEmpty();
235+
236+
// Hunter has no requests, low priority.
237+
if (actions == null && !hasMultiple) {
238+
return newPriority;
239+
}
240+
241+
if (action != null) {
242+
newPriority = action.getPriority();
243+
}
244+
245+
if (hasMultiple) {
246+
for (int i = 0, n = actions.size(); i < n; i++) {
247+
Priority actionPriority = actions.get(i).getPriority();
248+
if (actionPriority.ordinal() > newPriority.ordinal()) {
249+
newPriority = actionPriority;
250+
}
251+
}
252+
}
253+
254+
return newPriority;
255+
}
256+
209257
boolean cancel() {
210258
return action == null
211259
&& (actions == null || actions.isEmpty())
@@ -266,6 +314,10 @@ Picasso.LoadedFrom getLoadedFrom() {
266314
return loadedFrom;
267315
}
268316

317+
Priority getPriority() {
318+
return priority;
319+
}
320+
269321
static void updateThreadName(Request data) {
270322
String name = data.getName();
271323

picasso/src/main/java/com/squareup/picasso/Picasso.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,17 @@ public interface RequestTransformer {
8888
};
8989
}
9090

91+
/**
92+
* The priority of a request.
93+
*
94+
* @see RequestCreator#priority(Priority)
95+
*/
96+
public enum Priority {
97+
LOW,
98+
NORMAL,
99+
HIGH
100+
}
101+
91102
static final String TAG = "Picasso";
92103
static final Handler HANDLER = new Handler(Looper.getMainLooper()) {
93104
@Override public void handleMessage(Message msg) {

picasso/src/main/java/com/squareup/picasso/PicassoExecutorService.java

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,10 @@
1818
import android.net.ConnectivityManager;
1919
import android.net.NetworkInfo;
2020
import android.telephony.TelephonyManager;
21-
import java.util.concurrent.LinkedBlockingQueue;
21+
22+
import java.util.concurrent.Future;
23+
import java.util.concurrent.FutureTask;
24+
import java.util.concurrent.PriorityBlockingQueue;
2225
import java.util.concurrent.ThreadPoolExecutor;
2326
import java.util.concurrent.TimeUnit;
2427

@@ -33,7 +36,7 @@ class PicassoExecutorService extends ThreadPoolExecutor {
3336

3437
PicassoExecutorService() {
3538
super(DEFAULT_THREAD_COUNT, DEFAULT_THREAD_COUNT, 0, TimeUnit.MILLISECONDS,
36-
new LinkedBlockingQueue<Runnable>(), new Utils.PicassoThreadFactory());
39+
new PriorityBlockingQueue<Runnable>(), new Utils.PicassoThreadFactory());
3740
}
3841

3942
void adjustThreadCount(NetworkInfo info) {
@@ -78,4 +81,31 @@ private void setThreadCount(int threadCount) {
7881
setCorePoolSize(threadCount);
7982
setMaximumPoolSize(threadCount);
8083
}
84+
85+
@Override
86+
public Future<?> submit(Runnable task) {
87+
PicassoFutureTask ftask = new PicassoFutureTask((BitmapHunter) task);
88+
execute(ftask);
89+
return ftask;
90+
}
91+
92+
private static final class PicassoFutureTask extends FutureTask<BitmapHunter>
93+
implements Comparable<PicassoFutureTask> {
94+
private final BitmapHunter hunter;
95+
96+
public PicassoFutureTask(BitmapHunter hunter) {
97+
super(hunter, null);
98+
this.hunter = hunter;
99+
}
100+
101+
@Override
102+
public int compareTo(PicassoFutureTask other) {
103+
Picasso.Priority p1 = hunter.getPriority();
104+
Picasso.Priority p2 = other.hunter.getPriority();
105+
106+
// High-priority requests are "lesser" so they are sorted to the front.
107+
// Equal priorities are sorted by sequence number to provide FIFO ordering.
108+
return (p1 == p2 ? hunter.sequence - other.hunter.sequence : p2.ordinal() - p1.ordinal());
109+
}
110+
}
81111
}

picasso/src/main/java/com/squareup/picasso/Request.java

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import android.graphics.Bitmap;
1919
import android.net.Uri;
20+
import com.squareup.picasso.Picasso.Priority;
2021
import java.util.ArrayList;
2122
import java.util.List;
2223
import java.util.concurrent.TimeUnit;
@@ -74,10 +75,13 @@ public final class Request {
7475
public final boolean hasRotationPivot;
7576
/** Target image config for decoding. */
7677
public final Bitmap.Config config;
78+
/** The priority of this request. */
79+
public final Priority priority;
7780

7881
private Request(Uri uri, int resourceId, List<Transformation> transformations, int targetWidth,
7982
int targetHeight, boolean centerCrop, boolean centerInside, float rotationDegrees,
80-
float rotationPivotX, float rotationPivotY, boolean hasRotationPivot, Bitmap.Config config) {
83+
float rotationPivotX, float rotationPivotY, boolean hasRotationPivot, Bitmap.Config config,
84+
Priority priority) {
8185
this.uri = uri;
8286
this.resourceId = resourceId;
8387
if (transformations == null) {
@@ -94,6 +98,7 @@ private Request(Uri uri, int resourceId, List<Transformation> transformations, i
9498
this.rotationPivotY = rotationPivotY;
9599
this.hasRotationPivot = hasRotationPivot;
96100
this.config = config;
101+
this.priority = priority;
97102
}
98103

99104
@Override public String toString() {
@@ -185,6 +190,7 @@ public static final class Builder {
185190
private boolean hasRotationPivot;
186191
private List<Transformation> transformations;
187192
private Bitmap.Config config;
193+
private Priority priority;
188194

189195
/** Start building a request using the specified {@link Uri}. */
190196
public Builder(Uri uri) {
@@ -216,6 +222,7 @@ private Builder(Request request) {
216222
transformations = new ArrayList<Transformation>(request.transformations);
217223
}
218224
config = request.config;
225+
priority = request.priority;
219226
}
220227

221228
boolean hasImage() {
@@ -226,6 +233,10 @@ boolean hasSize() {
226233
return targetWidth != 0;
227234
}
228235

236+
boolean hasPriority() {
237+
return priority != null;
238+
}
239+
229240
/**
230241
* Set the target image Uri.
231242
* <p>
@@ -343,6 +354,18 @@ public Builder config(Bitmap.Config config) {
343354
return this;
344355
}
345356

357+
/** Execute request using the specified priority. */
358+
public Builder priority(Priority priority) {
359+
if (priority == null) {
360+
throw new IllegalArgumentException("Priority invalid.");
361+
}
362+
if (this.priority != null) {
363+
throw new IllegalStateException("Priority already set.");
364+
}
365+
this.priority = priority;
366+
return this;
367+
}
368+
346369
/**
347370
* Add a custom transformation to be applied to the image.
348371
* <p>
@@ -370,8 +393,12 @@ public Request build() {
370393
if (centerInside && targetWidth == 0) {
371394
throw new IllegalStateException("Center inside requires calling resize.");
372395
}
396+
if (priority == null) {
397+
priority = Priority.NORMAL;
398+
}
373399
return new Request(uri, resourceId, transformations, targetWidth, targetHeight, centerCrop,
374-
centerInside, rotationDegrees, rotationPivotX, rotationPivotY, hasRotationPivot, config);
400+
centerInside, rotationDegrees, rotationPivotX, rotationPivotY, hasRotationPivot, config,
401+
priority);
375402
}
376403
}
377404
}

picasso/src/main/java/com/squareup/picasso/RequestCreator.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030

3131
import static com.squareup.picasso.BitmapHunter.forRequest;
3232
import static com.squareup.picasso.Picasso.LoadedFrom.MEMORY;
33+
import static com.squareup.picasso.Picasso.Priority;
3334
import static com.squareup.picasso.PicassoDrawable.setBitmap;
3435
import static com.squareup.picasso.PicassoDrawable.setPlaceholder;
3536
import static com.squareup.picasso.RemoteViewsAction.AppWidgetAction;
@@ -228,6 +229,18 @@ public RequestCreator config(Bitmap.Config config) {
228229
return this;
229230
}
230231

232+
/**
233+
* Set the priority of this request.
234+
* <p>
235+
* This will affect the order in which the requests execute but does not guarantee it.
236+
* By default, all requests have {@link Priority#NORMAL} priority, except for
237+
* {@link #fetch()} requests, which have {@link Priority#LOW} priority by default.
238+
*/
239+
public RequestCreator priority(Priority priority) {
240+
data.priority(priority);
241+
return this;
242+
}
243+
231244
/**
232245
* Add a custom transformation to be applied to the image.
233246
* <p>
@@ -292,6 +305,11 @@ public void fetch() {
292305
throw new IllegalStateException("Fit cannot be used with fetch.");
293306
}
294307
if (data.hasImage()) {
308+
// Fetch requests have lower priority by default.
309+
if (!data.hasPriority()) {
310+
data.priority(Priority.LOW);
311+
}
312+
295313
Request request = createRequest(started);
296314
String key = createKey(request, new StringBuilder());
297315

0 commit comments

Comments
 (0)