-
Notifications
You must be signed in to change notification settings - Fork 4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement request group and pause/resume support #665
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
package com.example.picasso; | ||
|
||
import android.content.Context; | ||
import android.widget.AbsListView; | ||
|
||
import com.squareup.picasso.Picasso; | ||
|
||
public class SampleScrollListener implements AbsListView.OnScrollListener { | ||
private final Context context; | ||
|
||
public SampleScrollListener(Context context) { | ||
this.context = context; | ||
} | ||
|
||
@Override | ||
public void onScrollStateChanged(AbsListView view, int scrollState) { | ||
final Picasso picasso = Picasso.with(context); | ||
if (scrollState == SCROLL_STATE_IDLE || scrollState == SCROLL_STATE_TOUCH_SCROLL) { | ||
picasso.resumeTag(context); | ||
} else { | ||
picasso.pauseTag(context); | ||
} | ||
} | ||
|
||
@Override | ||
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, | ||
int totalItemCount) { | ||
// Do nothing. | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -39,12 +39,13 @@ public RequestWeakReference(Action action, T referent, ReferenceQueue<? super T> | |
final int errorResId; | ||
final Drawable errorDrawable; | ||
final String key; | ||
final Object tag; | ||
|
||
boolean willReplay; | ||
boolean cancelled; | ||
|
||
Action(Picasso picasso, T target, Request request, boolean skipCache, boolean noFade, | ||
int errorResId, Drawable errorDrawable, String key) { | ||
int errorResId, Drawable errorDrawable, String key, Object tag) { | ||
this.picasso = picasso; | ||
this.request = request; | ||
this.target = new RequestWeakReference<T>(this, target, picasso.referenceQueue); | ||
|
@@ -53,6 +54,7 @@ public RequestWeakReference(Action action, T referent, ReferenceQueue<? super T> | |
this.errorResId = errorResId; | ||
this.errorDrawable = errorDrawable; | ||
this.key = key; | ||
this.tag = (tag != null ? tag : this); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is using There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Two reasons for using 'this' here:
|
||
} | ||
|
||
abstract void complete(Bitmap result, Picasso.LoadedFrom from); | ||
|
@@ -90,4 +92,8 @@ Picasso getPicasso() { | |
Priority getPriority() { | ||
return request.priority; | ||
} | ||
|
||
Object getTag() { | ||
return tag; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,10 +27,12 @@ | |
import android.os.Looper; | ||
import android.os.Message; | ||
import java.util.ArrayList; | ||
import java.util.HashSet; | ||
import java.util.Iterator; | ||
import java.util.LinkedHashMap; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.Set; | ||
import java.util.WeakHashMap; | ||
import java.util.concurrent.ExecutorService; | ||
|
||
|
@@ -45,6 +47,7 @@ | |
import static com.squareup.picasso.Utils.VERB_DELIVERED; | ||
import static com.squareup.picasso.Utils.VERB_ENQUEUED; | ||
import static com.squareup.picasso.Utils.VERB_IGNORED; | ||
import static com.squareup.picasso.Utils.VERB_PAUSED; | ||
import static com.squareup.picasso.Utils.VERB_REPLAYING; | ||
import static com.squareup.picasso.Utils.VERB_RETRYING; | ||
import static com.squareup.picasso.Utils.getLogIdsForHunter; | ||
|
@@ -67,6 +70,9 @@ class Dispatcher { | |
static final int HUNTER_BATCH_COMPLETE = 8; | ||
static final int NETWORK_STATE_CHANGE = 9; | ||
static final int AIRPLANE_MODE_CHANGE = 10; | ||
static final int TAG_PAUSE = 11; | ||
static final int TAG_RESUME = 12; | ||
static final int REQUEST_BATCH_RESUME = 13; | ||
|
||
private static final String DISPATCHER_THREAD_NAME = "Dispatcher"; | ||
private static final int BATCH_DELAY = 200; // ms | ||
|
@@ -77,6 +83,8 @@ class Dispatcher { | |
final Downloader downloader; | ||
final Map<String, BitmapHunter> hunterMap; | ||
final Map<Object, Action> failedActions; | ||
final Map<Object, Action> pausedActions; | ||
final Set<Object> pausedTags; | ||
final Handler handler; | ||
final Handler mainThreadHandler; | ||
final Cache cache; | ||
|
@@ -95,6 +103,8 @@ class Dispatcher { | |
this.service = service; | ||
this.hunterMap = new LinkedHashMap<String, BitmapHunter>(); | ||
this.failedActions = new WeakHashMap<Object, Action>(); | ||
this.pausedActions = new WeakHashMap<Object, Action>(); | ||
this.pausedTags = new HashSet<Object>(); | ||
this.handler = new DispatcherHandler(dispatcherThread.getLooper(), this); | ||
this.downloader = downloader; | ||
this.mainThreadHandler = mainThreadHandler; | ||
|
@@ -121,6 +131,14 @@ void dispatchCancel(Action action) { | |
handler.sendMessage(handler.obtainMessage(REQUEST_CANCEL, action)); | ||
} | ||
|
||
void dispatchPauseTag(Object tag) { | ||
handler.sendMessage(handler.obtainMessage(TAG_PAUSE, tag)); | ||
} | ||
|
||
void dispatchResumeTag(Object tag) { | ||
handler.sendMessage(handler.obtainMessage(TAG_RESUME, tag)); | ||
} | ||
|
||
void dispatchComplete(BitmapHunter hunter) { | ||
handler.sendMessage(handler.obtainMessage(HUNTER_COMPLETE, hunter)); | ||
} | ||
|
@@ -143,6 +161,15 @@ void dispatchAirplaneModeChange(boolean airplaneMode) { | |
} | ||
|
||
void performSubmit(Action action) { | ||
if (pausedTags.contains(action.getTag())) { | ||
pausedActions.put(action.getTarget(), action); | ||
if (action.getPicasso().loggingEnabled) { | ||
log(OWNER_DISPATCHER, VERB_PAUSED, action.request.logId(), | ||
"because tag '" + action.getTag() + "' is paused"); | ||
} | ||
return; | ||
} | ||
|
||
BitmapHunter hunter = hunterMap.get(action.getKey()); | ||
if (hunter != null) { | ||
hunter.attach(action); | ||
|
@@ -178,12 +205,101 @@ void performCancel(Action action) { | |
} | ||
} | ||
} | ||
|
||
if (pausedTags.contains(action.getTag())) { | ||
pausedActions.remove(action.getTarget()); | ||
if (action.getPicasso().loggingEnabled) { | ||
log(OWNER_DISPATCHER, VERB_CANCELED, action.getRequest().logId(), | ||
"because paused request got canceled"); | ||
} | ||
} | ||
|
||
Action remove = failedActions.remove(action.getTarget()); | ||
if (remove != null && remove.getPicasso().loggingEnabled) { | ||
log(OWNER_DISPATCHER, VERB_CANCELED, remove.getRequest().logId(), "from replaying"); | ||
} | ||
} | ||
|
||
void performPauseTag(Object tag) { | ||
// Trying to pause a tag that is already paused. | ||
if (!pausedTags.add(tag)) { | ||
return; | ||
} | ||
|
||
// Go through all active hunters and detach/pause the requests | ||
// that have the paused tag. | ||
for (Iterator<BitmapHunter> it = hunterMap.values().iterator(); it.hasNext();) { | ||
BitmapHunter hunter = it.next(); | ||
boolean loggingEnabled = hunter.getPicasso().loggingEnabled; | ||
|
||
Action single = hunter.getAction(); | ||
List<Action> joined = hunter.getActions(); | ||
boolean hasMultiple = joined != null && !joined.isEmpty(); | ||
|
||
// Hunter has no requests, bail early. | ||
if (single == null && !hasMultiple) { | ||
continue; | ||
} | ||
|
||
if (single != null && single.getTag().equals(tag)) { | ||
hunter.detach(single); | ||
pausedActions.put(single.getTarget(), single); | ||
if (loggingEnabled) { | ||
log(OWNER_DISPATCHER, VERB_PAUSED, single.request.logId(), | ||
"because tag '" + tag + "' was paused"); | ||
} | ||
} | ||
|
||
if (hasMultiple) { | ||
for (int i = joined.size() - 1; i >= 0; i--) { | ||
Action action = joined.get(i); | ||
if (!action.getTag().equals(tag)) { | ||
continue; | ||
} | ||
|
||
hunter.detach(action); | ||
pausedActions.put(action.getTarget(), action); | ||
if (loggingEnabled) { | ||
log(OWNER_DISPATCHER, VERB_PAUSED, action.request.logId(), | ||
"because tag '" + tag + "' was paused"); | ||
} | ||
} | ||
} | ||
|
||
// Check if the hunter can be cancelled in case all its requests | ||
// had the tag being paused here. | ||
if (hunter.cancel()) { | ||
it.remove(); | ||
if (loggingEnabled) { | ||
log(OWNER_DISPATCHER, VERB_CANCELED, getLogIdsForHunter(hunter), "all actions paused"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nice |
||
} | ||
} | ||
} | ||
} | ||
|
||
void performResumeTag(Object tag) { | ||
// Trying to resume a tag that is not paused. | ||
if (!pausedTags.remove(tag)) { | ||
return; | ||
} | ||
|
||
List<Action> batch = null; | ||
for (Iterator<Action> i = pausedActions.values().iterator(); i.hasNext();) { | ||
Action action = i.next(); | ||
if (action.getTag().equals(tag)) { | ||
if (batch == null) { | ||
batch = new ArrayList<Action>(); | ||
} | ||
batch.add(action); | ||
i.remove(); | ||
} | ||
} | ||
|
||
if (batch != null) { | ||
mainThreadHandler.sendMessage(mainThreadHandler.obtainMessage(REQUEST_BATCH_RESUME, batch)); | ||
} | ||
} | ||
|
||
void performRetry(BitmapHunter hunter) { | ||
if (hunter.isCancelled()) return; | ||
|
||
|
@@ -350,6 +466,16 @@ public DispatcherHandler(Looper looper, Dispatcher dispatcher) { | |
dispatcher.performCancel(action); | ||
break; | ||
} | ||
case TAG_PAUSE: { | ||
Object tag = msg.obj; | ||
dispatcher.performPauseTag(tag); | ||
break; | ||
} | ||
case TAG_RESUME: { | ||
Object tag = msg.obj; | ||
dispatcher.performResumeTag(tag); | ||
break; | ||
} | ||
case HUNTER_COMPLETE: { | ||
BitmapHunter hunter = (BitmapHunter) msg.obj; | ||
dispatcher.performComplete(hunter); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No settling state :( Damn you,
AbsListView
.