@Test public void testOnFrameReadyWithNullResourceDoesNotClearPreviousFrame() { // Force the loader to create a real Handler by passing null. loader = createGifFrameLoader(null); DelayTarget previous = mock(DelayTarget.class); Request previousRequest = mock(Request.class); when(previous.getRequest()).thenReturn(previousRequest); when(previous.getResource()).thenReturn(Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888)); DelayTarget current = mock(DelayTarget.class); when(current.getResource()).thenReturn(null); loader.onFrameReady(previous); loader.onFrameReady(current); verify(previousRequest, never()).clear(); }
@Test public void testOnFrameReadyClearsPreviousFrame() { // Force the loader to create a real Handler. loader = createGifFrameLoader(null); DelayTarget previous = mock(DelayTarget.class); Request previousRequest = mock(Request.class); when(previous.getRequest()).thenReturn(previousRequest); when(previous.getResource()).thenReturn(Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888)); DelayTarget current = mock(DelayTarget.class); when(current.getResource()).thenReturn(Bitmap.createBitmap(100, 100, Bitmap.Config.RGB_565)); loader.onFrameReady(previous); loader.onFrameReady(current); verify(requestManager).clear(eq(previous)); }
private boolean clearRemoveAndMaybeRecycle(@Nullable Request request, boolean isSafeToRecycle) { if (request == null) { // If the Request is null, the request is already cleared and we don't need to search further // for its owner. return true; } boolean isOwnedByUs = requests.remove(request); // Avoid short circuiting. isOwnedByUs = pendingRequests.remove(request) || isOwnedByUs; if (isOwnedByUs) { request.clear(); if (isSafeToRecycle) { request.recycle(); } } return isOwnedByUs; }
private void untrackOrDelegate(Target<?> target) { boolean isOwnedByUs = untrack(target); // We'll end up here if the Target was cleared after the RequestManager that started the request // is destroyed. That can happen for at least two reasons: // 1. We call clear() on a background thread using something other than Application Context // RequestManager. // 2. The caller retains a reference to the RequestManager after the corresponding Activity or // Fragment is destroyed, starts a load with it, and then clears that load with a different // RequestManager. Callers seem especially likely to do this in retained Fragments (#2262). // // #1 is always an error. At best the caller is leaking memory briefly in something like an // AsyncTask. At worst the caller is leaking an Activity or Fragment for a sustained period of // time if they do something like reference the Activity RequestManager in a long lived // background thread or task. // // #2 is always an error. Callers shouldn't be starting new loads using RequestManagers after // the corresponding Activity or Fragment is destroyed because retaining any reference to the // RequestManager leaks memory. It's possible that there's some brief period of time during or // immediately after onDestroy where this is reasonable, but I can't think of why. if (!isOwnedByUs && !glide.removeFromManagers(target) && target.getRequest() != null) { Request request = target.getRequest(); target.setRequest(null); request.clear(); } }
@Test public void removeFromManagers_afterRequestManagerRemoved_clearsRequest() { target = requestManager.load(mockUri("content://uri")).into(new SimpleTarget<Drawable>() { @Override public void onResourceReady(Drawable resource, Transition<? super Drawable> transition) { // Do nothing. } }); Request request = Preconditions.checkNotNull(target.getRequest()); requestManager.onDestroy(); requestManager.clear(target); assertThat(target.getRequest()).isNull(); assertThat(request.isCancelled()).isTrue(); }
/** * Starts tracking the given request. */ public void runRequest(Request request) { requests.add(request); if (!isPaused) { request.begin(); } else { pendingRequests.add(request); } }
/** * Stops tracking the given request, clears, and recycles it, and returns {@code true} if the * request was removed or {@code false} if the request was not found. */ public boolean clearRemoveAndRecycle(Request request) { boolean isOwnedByUs = request != null && (requests.remove(request) || pendingRequests.remove(request)); if (isOwnedByUs) { request.clear(); request.recycle(); } return isOwnedByUs; }
/** * Stops any in progress requests. */ public void pauseRequests() { isPaused = true; for (Request request : Util.getSnapshot(requests)) { if (request.isRunning()) { request.pause(); pendingRequests.add(request); } } }
/** * Starts any not yet completed or failed requests. */ public void resumeRequests() { isPaused = false; for (Request request : Util.getSnapshot(requests)) { if (!request.isComplete() && !request.isCancelled() && !request.isRunning()) { request.begin(); } } pendingRequests.clear(); }
/** * Cancels all requests and clears their resources. * * <p>After this call requests cannot be restarted. */ public void clearRequests() { for (Request request : Util.getSnapshot(requests)) { clearRemoveAndRecycle(request); } pendingRequests.clear(); }
/** * Restarts failed requests and cancels and restarts in progress requests. */ public void restartRequests() { for (Request request : Util.getSnapshot(requests)) { if (!request.isComplete() && !request.isCancelled()) { // Ensure the request will be restarted in onResume. request.pause(); if (!isPaused) { request.begin(); } else { pendingRequests.add(request); } } } }
boolean untrack(Target<?> target) { Request request = target.getRequest(); // If the Target doesn't have a request, it's already been cleared. if (request == null) { return true; } if (requestTracker.clearRemoveAndRecycle(request)) { targetTracker.untrack(target); target.setRequest(null); return true; } else { return false; } }
private void runTestFileDefaultLoader() { File file = new File("fake"); mockUri(Uri.fromFile(file)); requestManager.load(file).into(target); requestManager.load(file).into(imageView); verify(target).onResourceReady(isA(BitmapDrawable.class), isA(Transition.class)); verify(target).setRequest((Request) notNull()); assertNotNull(imageView.getDrawable()); }
@Test public void testUrlDefaultLoader() throws MalformedURLException { URL url = new URL("http://www.google.com"); requestManager.load(url).into(target); requestManager.load(url).into(imageView); verify(target).onResourceReady(isA(BitmapDrawable.class), isA(Transition.class)); verify(target).setRequest((Request) notNull()); assertNotNull(imageView.getDrawable()); }
private void runTestUriDefaultLoader() { Uri uri = Uri.parse("content://test/something"); mockUri(uri); requestManager.load(uri).into(target); requestManager.load(uri).into(imageView); verify(target).onResourceReady(notNull(), isA(Transition.class)); verify(target).setRequest((Request) notNull()); assertNotNull(imageView.getDrawable()); }
private void runTestIntegerDefaultLoader() { int integer = android.R.drawable.star_on; mockUri("android.resource://" + "android" + "/drawable/star_on"); requestManager.load(integer).into(target); requestManager.load(integer).into(imageView); verify(target).onResourceReady(isA(BitmapDrawable.class), isA(Transition.class)); verify(target).setRequest((Request) notNull()); assertNotNull(imageView.getDrawable()); }
@Test public void testClearsTargetInOnResourceReady() { Request request = mock(Request.class); PreloadTarget<Object> target = PreloadTarget.obtain(requestManager, 100, 100); target.setRequest(request); target.onResourceReady(new Object(), null); verify(requestManager).clear(eq(target)); }
@Test public void testClearsAddedRequestsOnDestroy() { Request request = mock(Request.class); tracker.addRequest(request); tracker.clearRequests(); verify(request).clear(); verify(request).recycle(); }
@Test public void testClearRemoveAndRecycle_withUnTrackedRequest_doesNothingAndReturnsFalse() { Request request = mock(Request.class); assertThat(tracker.clearRemoveAndRecycle(request)).isFalse(); verify(request, never()).clear(); verify(request, never()).recycle(); }
@Test public void testClearRemoveAndRecycle_withTrackedRequest_clearsRecyclesAndReturnsTrue() { Request request = mock(Request.class); tracker.addRequest(request); assertThat(tracker.clearRemoveAndRecycle(request)).isTrue(); verify(request).clear(); verify(request).recycle(); }
@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 testCanAddAndRemoveRequest() { Request request = mock(Request.class); tracker.addRequest(request); tracker.clearRemoveAndRecycle(request); tracker.clearRequests(); verify(request, times(1)).clear(); }
@Test public void testClearsCompletedLoadOnFrameReadyIfCleared() { // Force the loader to create a real Handler by passing null; loader = createGifFrameLoader(null); loader.clear(); DelayTarget delayTarget = mock(DelayTarget.class); Request request = mock(Request.class); when(delayTarget.getRequest()).thenReturn(request); loader.onFrameReady(delayTarget); verify(requestManager).clear(eq(delayTarget)); }
@Test public void testPausesInProgressRequestsWhenPaused() { Request request = mock(Request.class); when(request.isRunning()).thenReturn(true); tracker.addRequest(request); tracker.pauseRequests(); verify(request).pause(); }
@Test public void testDoesNotClearCompleteRequestsWhenPaused() { Request request = mock(Request.class); 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 testDoesNotClearFailedRequestsWhenPaused() { Request request = mock(Request.class); when(request.isFailed()).thenReturn(true); tracker.addRequest(request); tracker.pauseRequests(); verify(request, never()).clear(); }
@Test public void testRestartsStoppedRequestWhenResumed() { Request request = mock(Request.class); tracker.addRequest(request); tracker.resumeRequests(); verify(request).begin(); }
@Test public void testDoesNotRestartCompletedRequestsWhenResumed() { Request request = mock(Request.class); when(request.isComplete()).thenReturn(true); tracker.addRequest(request); tracker.resumeRequests(); verify(request, never()).begin(); }
@Test public void testDoesRestartFailedRequestsWhenResumed() { Request request = mock(Request.class); when(request.isFailed()).thenReturn(true); tracker.addRequest(request); tracker.resumeRequests(); verify(request).begin(); }
@Test public void testDoesNotStartStartedRequestsWhenResumed() { Request request = mock(Request.class); when(request.isRunning()).thenReturn(true); tracker.addRequest(request); tracker.resumeRequests(); verify(request, never()).begin(); }
@Test public void testAvoidsConcurrentModificationWhenResuming() { Request first = mock(Request.class); Request second = mock(Request.class); doAnswer(new ClearAndRemoveRequest(second)).when(first).begin(); tracker.addRequest(mock(Request.class)); tracker.addRequest(first); tracker.addRequest(second); tracker.resumeRequests(); }
@Test public void testAvoidsConcurrentModificationWhenPausing() { Request first = mock(Request.class); Request second = mock(Request.class); when(first.isRunning()).thenReturn(true); doAnswer(new ClearAndRemoveRequest(second)).when(first).pause(); tracker.addRequest(mock(Request.class)); tracker.addRequest(first); tracker.addRequest(second); tracker.pauseRequests(); }
@Test public void testAvoidsConcurrentModificationWhenClearing() { Request first = mock(Request.class); Request second = mock(Request.class); doAnswer(new ClearAndRemoveRequest(second)).when(first).clear(); tracker.addRequest(mock(Request.class)); tracker.addRequest(first); tracker.addRequest(second); tracker.clearRequests(); }
@Test public void testRestartsFailedRequestRestart() { Request request = mock(Request.class); when(request.isFailed()).thenReturn(true); tracker.addRequest(request); tracker.restartRequests(); verify(request).begin(); }
@Test public void testPausesAndRestartsNotYetFinishedRequestsOnRestart() { Request request = mock(Request.class); when(request.isComplete()).thenReturn(false); tracker.addRequest(request); tracker.restartRequests(); verify(request).pause(); verify(request).begin(); }