提交 43c08254 编写于 作者: S Sam Judd

Don't start new requests while paused.

Fixes #90
上级 f3c7a66f
......@@ -108,7 +108,7 @@ public class GenericRequestBuilderTest {
@Test
public void testAddsNewRequestToRequestTracker() {
getNullModelRequest().into(mock(Target.class));
verify(requestTracker).addRequest(any(Request.class));
verify(requestTracker).runRequest(any(Request.class));
}
@Test
......
......@@ -32,6 +32,7 @@ import com.bumptech.glide.load.resource.bytes.BytesResource;
import com.bumptech.glide.load.resource.drawable.GlideDrawable;
import com.bumptech.glide.load.resource.gif.GifDrawable;
import com.bumptech.glide.load.resource.transcode.ResourceTranscoder;
import com.bumptech.glide.manager.Lifecycle;
import com.bumptech.glide.request.Request;
import com.bumptech.glide.request.RequestListener;
import com.bumptech.glide.request.animation.GlideAnimation;
......@@ -83,6 +84,7 @@ import static org.mockito.Mockito.when;
public class GlideTest {
private Target target = null;
private ImageView imageView;
private RequestManager requestManager;
@Before
public void setUp() throws Exception {
......@@ -129,6 +131,9 @@ public class GlideTest {
.thenReturn(mockUrlLoader);
Glide.get(getContext()).register(GlideUrl.class, InputStream.class, mockUrlLoaderFactory);
Lifecycle lifecycle = mock(Lifecycle.class);
requestManager = new RequestManager(getContext(), lifecycle);
requestManager.resumeRequests();
}
@After
......@@ -214,7 +219,7 @@ public class GlideTest {
Encoder<File> sourceEncoder = mock(Encoder.class);
when(sourceEncoder.getId()).thenReturn("sourceEncoderId");
Glide.with(getContext())
requestManager
.using(modelLoader, File.class)
.load(glideUrl)
.as(File.class)
......@@ -248,8 +253,8 @@ public class GlideTest {
File file = new File("fake");
mockUri(Uri.fromFile(file));
Glide.with(getContext()).load(file).into(target);
Glide.with(getContext()).load(file).into(imageView);
requestManager.load(file).into(target);
requestManager.load(file).into(imageView);
verify(target).onResourceReady(any(Resource.class), any(GlideAnimation.class));
verify(target).setRequest((Request) notNull());
......@@ -261,8 +266,8 @@ public class GlideTest {
public void testUrlDefaultLoader() throws MalformedURLException {
URL url = new URL("http://www.google.com");
Glide.with(getContext()).load(url).into(target);
Glide.with(getContext()).load(url).into(imageView);
requestManager.load(url).into(target);
requestManager.load(url).into(imageView);
verify(target).onResourceReady(any(Resource.class), any(GlideAnimation.class));
verify(target).setRequest((Request) notNull());
......@@ -275,7 +280,7 @@ public class GlideTest {
Uri uri = Uri.parse("content://something/else");
mockUri(uri);
Glide.with(getContext()).load(uri).asBitmap().into(target);
requestManager.load(uri).asBitmap().into(target);
verify(target).onResourceReady(any(Bitmap.class), any(GlideAnimation.class));
}
......@@ -290,7 +295,7 @@ public class GlideTest {
when(transcoder.getId()).thenReturn("bytes");
when(transcoder.transcode(any(Resource.class))).thenReturn(new BytesResource(bytes));
Glide.with(getContext())
requestManager
.load(uri)
.asBitmap()
.transcode(transcoder, byte[].class)
......@@ -304,7 +309,7 @@ public class GlideTest {
Uri uri = Uri.parse("content://something/else");
mockUri(uri);
Glide.with(getContext()).load(uri).asBitmap().toBytes().into(target);
requestManager.load(uri).asBitmap().toBytes().into(target);
verify(target).onResourceReady(any(byte[].class), any(GlideAnimation.class));
}
......@@ -330,8 +335,8 @@ public class GlideTest {
Uri uri = Uri.parse("content://test/something");
mockUri(uri);
Glide.with(getContext()).load(uri).into(target);
Glide.with(getContext()).load(uri).into(imageView);
requestManager.load(uri).into(target);
requestManager.load(uri).into(imageView);
verify(target).onResourceReady(anyObject(), any(GlideAnimation.class));
verify(target).setRequest((Request) notNull());
......@@ -391,7 +396,7 @@ public class GlideTest {
}
private void runTestStringDefaultLoader(String string) {
Glide.with(getContext())
requestManager
.load(string)
.listener(new RequestListener<String, GlideDrawable>() {
@Override
......@@ -410,7 +415,7 @@ public class GlideTest {
}
})
.into(target);
Glide.with(getContext()).load(string).into(imageView);
requestManager.load(string).into(imageView);
verify(target).onResourceReady(any(Resource.class), any(GlideAnimation.class));
verify(target).setRequest((Request) notNull());
......@@ -439,8 +444,8 @@ public class GlideTest {
int integer = 1234;
mockUri("android.resource://" + getContext().getPackageName() + "/" + integer);
Glide.with(getContext()).load(integer).into(target);
Glide.with(getContext()).load(integer).into(imageView);
requestManager.load(integer).into(target);
requestManager.load(integer).into(imageView);
verify(target).onResourceReady(any(Resource.class), any(GlideAnimation.class));
verify(target).setRequest((Request) notNull());
......@@ -451,8 +456,8 @@ public class GlideTest {
@Test
public void testByteArrayDefaultLoader() {
byte[] bytes = new byte[10];
Glide.with(getContext()).load(bytes).into(target);
Glide.with(getContext()).load(bytes).into(imageView);
requestManager.load(bytes).into(target);
requestManager.load(bytes).into(imageView);
verify(target).onResourceReady(any(Resource.class), any(GlideAnimation.class));
verify(target).setRequest((Request) notNull());
......@@ -465,8 +470,8 @@ public class GlideTest {
byte[] bytes = new byte[10];
String id = "test";
Glide.with(getContext()).load(bytes, id).into(target);
Glide.with(getContext()).load(bytes, id).into(imageView);
requestManager.load(bytes, id).into(target);
requestManager.load(bytes, id).into(imageView);
verify(target).onResourceReady(any(Resource.class), any(GlideAnimation.class));
verify(target).setRequest((Request) notNull());
......@@ -477,7 +482,7 @@ public class GlideTest {
@Test(expected = Exception.class)
public void testUnregisteredModelThrowsException() {
Float unregistered = 0.5f;
Glide.with(getContext()).load(unregistered).into(target);
requestManager.load(unregistered).into(target);
}
@Test
......@@ -485,7 +490,7 @@ public class GlideTest {
public void testUnregisteredModelWithGivenLoaderDoesNotThrow() {
Float unregistered = 0.5f;
StreamModelLoader<Float> mockLoader = mockStreamModelLoader(Float.class);
Glide.with(getContext())
requestManager
.using(mockLoader)
.load(unregistered)
.into(target);
......@@ -496,7 +501,7 @@ public class GlideTest {
public void testNonDefaultModelWithRegisteredFactoryDoesNotThrow() {
registerMockStreamModelLoader(Float.class);
Glide.with(getContext()).load(0.5f).into(target);
requestManager.load(0.5f).into(target);
}
@Test
......@@ -505,7 +510,7 @@ public class GlideTest {
InputStream testGifData = openResource("test.gif");
mockUri(Uri.parse(fakeUri), testGifData);
Glide.with(getContext())
requestManager
.load(fakeUri)
.asGif()
.into(target);
......@@ -519,7 +524,7 @@ public class GlideTest {
InputStream testGifData = openResource("test.gif");
mockUri(Uri.parse(fakeUri), testGifData);
Glide.with(getContext())
requestManager
.load(fakeUri)
.asGif()
.toBytes()
......@@ -532,7 +537,7 @@ public class GlideTest {
public void testReceivesBitmapBytes() {
String fakeUri = "content://fake";
mockUri(fakeUri);
Glide.with(getContext())
requestManager
.load(fakeUri)
.asBitmap()
.toBytes()
......@@ -546,7 +551,7 @@ public class GlideTest {
String fakeUri = "content://fake";
mockUri(fakeUri);
final Bitmap expected = Bitmap.createBitmap(1234, 6432, Bitmap.Config.ALPHA_8);
Glide.with(getContext())
requestManager
.load(fakeUri)
.asBitmap()
.transcode(new ResourceTranscoder<Bitmap, Bitmap>() {
......@@ -567,17 +572,17 @@ public class GlideTest {
@Test
public void testNullModelInGenericImageLoadDoesNotThrow() {
Glide.with(getContext()).load((Double) null).into(target);
requestManager.load((Double) null).into(target);
}
@Test
public void testNullModelInGenericVideoLoadDoesNotThrow() {
Glide.with(getContext()).load((Float) null).into(target);
requestManager.load((Float) null).into(target);
}
@Test
public void testNullModelInGenericLoadDoesNotThrow() {
Glide.with(getContext()).load((Double) null).into(target);
requestManager.load((Double) null).into(target);
}
@Test
......@@ -585,7 +590,7 @@ public class GlideTest {
String nullString = null;
Drawable drawable = new ColorDrawable(Color.RED);
Glide.with(getContext())
requestManager
.load(nullString)
.placeholder(drawable)
.into(target);
......@@ -600,7 +605,7 @@ public class GlideTest {
Drawable placeholder = new ColorDrawable(Color.GREEN);
Drawable error = new ColorDrawable(Color.RED);
Glide.with(getContext())
requestManager
.load(nullString)
.placeholder(placeholder)
.error(error)
......@@ -614,7 +619,7 @@ public class GlideTest {
String nullString = null;
Drawable drawable = new ColorDrawable(Color.RED);
StreamModelLoader<String> modelLoader = mock(StreamModelLoader.class);
Glide.with(getContext())
requestManager
.using(modelLoader)
.load(nullString)
.placeholder(drawable)
......@@ -626,7 +631,7 @@ public class GlideTest {
@Test
public void testByteData() {
byte[] data = new byte[] { 1, 2, 3, 4, 5, 6 };
Glide.with(getContext()).load(data).into(target);
requestManager.load(data).into(target);
}
@SuppressWarnings("unchecked")
......
......@@ -65,14 +65,41 @@ public class RequestTrackerTest {
@Test
public void testDoesNotClearCompleteRequestsWhenPaused() {
Request request = mock(Request.class);
when(request.isComplete()).thenReturn(true);
tracker.addRequest(request);
when(request.isComplete()).thenReturn(true);
tracker.pauseRequests();
verify(request, never()).clear();
}
@Test
public void testStartsRequestOnRun() {
Request request = mock(Request.class);
tracker.runRequest(request);
verify(request).begin();
}
@Test
public void testDoesNotStartRequestOnRunIfPaused() {
Request request = mock(Request.class);
tracker.pauseRequests();
tracker.runRequest(request);
verify(request, never()).begin();
}
@Test
public void testStartsRequestAddedWhenPausedWhenResumed() {
Request request = mock(Request.class);
tracker.pauseRequests();
tracker.runRequest(request);
tracker.resumeRequests();
verify(request).begin();
}
@Test
public void testDoesNotClearFailedRequestsWhenPaused() {
Request request = mock(Request.class);
......@@ -149,4 +176,51 @@ public class RequestTrackerTest {
verify(request).clear();
verify(request).begin();
}
@Test
public void testDoesNotBeginFailedRequestOnRestartIfPaused() {
Request request = mock(Request.class);
when(request.isFailed()).thenReturn(true);
tracker.pauseRequests();
tracker.addRequest(request);
tracker.restartRequests();
verify(request, never()).begin();
}
@Test
public void testClearsFailedRequestOnRestartIfPaused() {
Request request = mock(Request.class);
when(request.isFailed()).thenReturn(true);
tracker.pauseRequests();
tracker.addRequest(request);
tracker.restartRequests();
verify(request).clear();
}
@Test
public void testDoesNotBeginIncompleteRequestsOnRestartIfPaused() {
Request request = mock(Request.class);
when(request.isFailed()).thenReturn(false);
when(request.isComplete()).thenReturn(false);
tracker.pauseRequests();
tracker.addRequest(request);
tracker.restartRequests();
verify(request, never()).begin();
}
@Test
public void testClearsIncompleteRequestsOnRestartIfPaused() {
Request request = mock(Request.class);
when(request.isFailed()).thenReturn(false);
when(request.isComplete()).thenReturn(false);
tracker.pauseRequests();
tracker.addRequest(request);
tracker.restartRequests();
verify(request).clear();
}
}
\ No newline at end of file
......@@ -191,6 +191,26 @@ public class GenericRequestTest {
assertTrue(request.isFailed());
}
@Test
public void testIsNotFailedAfterClear() {
GenericRequest request = harness.getRequest();
request.onResourceReady(null);
request.clear();
assertFalse(request.isFailed());
}
@Test
public void testIsNotFailedAfterBegin() {
GenericRequest request = harness.getRequest();
request.onResourceReady(null);
request.begin();
assertFalse(request.isFailed());
}
@Test
public void testIsCompleteAfterReceivingResource() {
GenericRequest request = harness.getRequest();
......@@ -201,6 +221,16 @@ public class GenericRequestTest {
assertTrue(request.isComplete());
}
@Test
public void testIsNotCompleteAfterClear() {
GenericRequest request = harness.getRequest();
when(harness.resource.get()).thenReturn(new Object());
request.onResourceReady(harness.resource);
request.clear();
assertFalse(request.isComplete());
}
@Test
public void testResourceIsNotCompleteWhenAskingCoordinatorIfCanSetImage() {
RequestCoordinator requestCoordinator = mock(RequestCoordinator.class);
......@@ -237,11 +267,25 @@ public class GenericRequestTest {
assertTrue(request.isFailed());
}
@Test
public void testIgnoresOnSizeReadyIfNotWaitingForSize() {
GenericRequest request = harness.getRequest();
request.begin();
request.onSizeReady(100, 100);
request.onSizeReady(100, 100);
verify(harness.engine, times(1)).load(eq(100), eq(100), any(ResourceDecoder.class), any(DataFetcher.class),
any(Encoder.class), any(ResourceDecoder.class), any(Transformation.class), any(ResourceEncoder.class),
any(ResourceTranscoder.class), any(Priority.class), anyBoolean(), any(DiskCacheStrategy.class),
any(ResourceCallback.class));
}
@Test
public void testEngineLoadPassedCorrectPriority() {
Priority expected = Priority.HIGH;
harness.priority = expected;
GenericRequest request = harness.getRequest();
request.begin();
request.onSizeReady(100, 100);
......@@ -260,6 +304,7 @@ public class GenericRequestTest {
any(DiskCacheStrategy.class), any(ResourceCallback.class))).thenReturn(loadStatus);
GenericRequest request = harness.getRequest();
request.begin();
request.onSizeReady(100, 100);
request.cancel();
......@@ -516,6 +561,8 @@ public class GenericRequestTest {
return null;
}
});
request.begin();
request.onSizeReady(100, 100);
verify(harness.requestListener).onResourceReady(anyObject(), anyObject(), any(Target.class), eq(true),
anyBoolean());
......@@ -656,6 +703,7 @@ public class GenericRequestTest {
public void testOnSizeReadyWithNullDataFetcherCallsOnException() {
GenericRequest<Object, Object, Object, Object> request = harness.getRequest();
when(harness.modelLoader.getResourceFetcher(anyObject(), anyInt(), anyInt())).thenReturn(null);
request.begin();
request.onSizeReady(100, 100);
verify(harness.requestListener).onException(any(Exception.class), anyObject(), any(Target.class),
......
......@@ -533,9 +533,8 @@ public class GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeT
Request request = buildRequest(target);
target.setRequest(request);
requestTracker.addRequest(request);
request.begin();
lifecycle.addListener(target);
requestTracker.runRequest(request);
return target;
}
......
......@@ -17,11 +17,20 @@ public class RequestTracker {
// can always make repeated requests into targets other than views, or use an activity manager in a fragment pager
// where holding strong references would steadily leak bitmaps and/or views.
private final Set<Request> requests = Collections.newSetFromMap(new WeakHashMap<Request, Boolean>());
private boolean isPaused;
/**
* Starts tracking the given request.
*/
public void addRequest(Request request) {
public void runRequest(Request request) {
requests.add(request);
if (!isPaused) {
request.begin();
}
}
// Exposed for testing.
void addRequest(Request request) {
requests.add(request);
}
......@@ -36,6 +45,7 @@ public class RequestTracker {
* Stops any in progress requests.
*/
public void pauseRequests() {
isPaused = true;
for (Request request : requests) {
if (!request.isComplete() && !request.isFailed()) {
request.clear();
......@@ -47,6 +57,7 @@ public class RequestTracker {
* Starts any not yet completed or failed requests.
*/
public void resumeRequests() {
isPaused = false;
for (Request request : requests) {
if (!request.isComplete() && !request.isRunning()) {
request.begin();
......@@ -69,10 +80,18 @@ public class RequestTracker {
public void restartRequests() {
for (Request request : requests) {
if (request.isFailed()) {
request.begin();
if (isPaused) {
// Ensure the request will be restarted in onResume.
request.clear();
} else {
request.begin();
}
} else if (!request.isComplete()) {
// Make sure we re-queue the request, we may just have not received the failure yet.
request.clear();
request.begin();
if (!isPaused) {
request.begin();
}
}
}
}
......
......@@ -37,6 +37,16 @@ import java.util.Queue;
public final class GenericRequest<A, T, Z, R> implements Request, SizeReadyCallback,
ResourceCallback {
private static final String TAG = "GenericRequest";
private static final Queue<GenericRequest> REQUEST_POOL = new ArrayDeque<GenericRequest>();
private enum Status {
PENDING,
RUNNING,
WAITING_FOR_SIZE,
COMPLETE,
FAILED,
CANCELLED,
}
private int placeholderResourceId;
private int errorResourceId;
......@@ -60,15 +70,11 @@ public final class GenericRequest<A, T, Z, R> implements Request, SizeReadyCallb
private Drawable placeholderDrawable;
private Drawable errorDrawable;
private boolean isCancelled;
private boolean isError;
private boolean loadedFromMemoryCache;
private Resource resource;
private Engine.LoadStatus loadStatus;
private boolean isRunning;
private long startTime;
private static final Queue<GenericRequest> REQUEST_POOL = new ArrayDeque<GenericRequest>();
private Status status;
@SuppressWarnings("unchecked")
public static <A, T, Z, R> GenericRequest<A, T, Z, R> obtain(
......@@ -120,7 +126,7 @@ public final class GenericRequest<A, T, Z, R> implements Request, SizeReadyCallb
}
private GenericRequest() {
// Empty.
}
@Override
......@@ -135,11 +141,8 @@ public final class GenericRequest<A, T, Z, R> implements Request, SizeReadyCallb
requestCoordinator = null;
transformation = null;
animationFactory = null;
isCancelled = false;
isError = false;
loadedFromMemoryCache = false;
loadStatus = null;
isRunning = false;
REQUEST_POOL.offer(this);
}
......@@ -184,6 +187,7 @@ public final class GenericRequest<A, T, Z, R> implements Request, SizeReadyCallb
this.overrideWidth = overrideWidth;
this.overrideHeight = overrideHeight;
this.diskCacheStrategy = diskCacheStrategy;
status = Status.PENDING;
// We allow null models by just setting an error drawable. Null models will always have empty providers, we
// simply skip our sanity checks in that unusual case.
......@@ -220,12 +224,12 @@ public final class GenericRequest<A, T, Z, R> implements Request, SizeReadyCallb
@Override
public void begin() {
startTime = LogTime.getLogTime();
isCancelled = false;
if (model == null) {
onException(null);
return;
}
status = Status.WAITING_FOR_SIZE;
if (overrideWidth > 0 && overrideHeight > 0) {
onSizeReady(overrideWidth, overrideHeight);
} else {
......@@ -236,7 +240,6 @@ public final class GenericRequest<A, T, Z, R> implements Request, SizeReadyCallb
if (canNotifyStatusChanged()) {
target.onLoadStarted(getPlaceholderDrawable());
}
isRunning = true;
}
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logV("finished run method in " + LogTime.getElapsedMillis(startTime));
......@@ -253,9 +256,8 @@ public final class GenericRequest<A, T, Z, R> implements Request, SizeReadyCallb
*
* @see #clear()
*/
public void cancel() {
isRunning = false;
isCancelled = true;
void cancel() {
status = Status.CANCELLED;
if (loadStatus != null) {
loadStatus.cancel();
loadStatus = null;
......@@ -290,7 +292,7 @@ public final class GenericRequest<A, T, Z, R> implements Request, SizeReadyCallb
*/
@Override
public boolean isRunning() {
return isRunning;
return status == Status.RUNNING || status == Status.WAITING_FOR_SIZE;
}
/**
......@@ -298,7 +300,7 @@ public final class GenericRequest<A, T, Z, R> implements Request, SizeReadyCallb
*/
@Override
public boolean isComplete() {
return resource != null;
return status == Status.COMPLETE;
}
/**
......@@ -306,7 +308,7 @@ public final class GenericRequest<A, T, Z, R> implements Request, SizeReadyCallb
*/
@Override
public boolean isFailed() {
return isError;
return status == Status.FAILED;
}
private void setErrorPlaceholder(Exception e) {
......@@ -343,9 +345,10 @@ public final class GenericRequest<A, T, Z, R> implements Request, SizeReadyCallb
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logV("Got onSizeReady in " + LogTime.getElapsedMillis(startTime));
}
if (isCancelled) {
if (status != Status.WAITING_FOR_SIZE) {
return;
}
status = Status.RUNNING;
width = Math.round(sizeMultiplier * width);
height = Math.round(sizeMultiplier * height);
......@@ -394,9 +397,10 @@ public final class GenericRequest<A, T, Z, R> implements Request, SizeReadyCallb
@SuppressWarnings("unchecked")
@Override
public void onResourceReady(Resource resource) {
isRunning = false;
if (!canSetResource()) {
resource.release();
// We can't set the status to complete before asking canSetResource().
status = Status.COMPLETE;
return;
}
Object received = resource != null ? resource.get() : null;
......@@ -409,6 +413,7 @@ public final class GenericRequest<A, T, Z, R> implements Request, SizeReadyCallb
return;
}
R result = (R) received;
status = Status.COMPLETE;
if (requestListener == null || !requestListener.onResourceReady(result, model, target, loadedFromMemoryCache,
isFirstReadyResource())) {
......@@ -433,8 +438,7 @@ public final class GenericRequest<A, T, Z, R> implements Request, SizeReadyCallb
Log.d(TAG, "load failed", e);
}
isRunning = false;
isError = true;
status = Status.FAILED;
//TODO: what if this is a thumbnail request?
if (requestListener == null || !requestListener.onException(e, model, target, isFirstReadyResource())) {
setErrorPlaceholder(e);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册