Skip to content

Commit

Permalink
Allow Requests to notify Targets when cleared after loads complete.
Browse files Browse the repository at this point in the history
Fixes #2555.
  • Loading branch information
sjudd committed Nov 18, 2017
1 parent d667220 commit 9c82c42
Show file tree
Hide file tree
Showing 12 changed files with 711 additions and 31 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.bumptech.glide;

import static com.bumptech.glide.test.Matchers.anyDrawable;
import static com.bumptech.glide.test.Matchers.anyTarget;
import static org.mockito.AdditionalMatchers.not;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyBoolean;
Expand All @@ -17,7 +19,6 @@
import com.bumptech.glide.load.engine.cache.MemoryCacheAdapter;
import com.bumptech.glide.request.FutureTarget;
import com.bumptech.glide.request.RequestListener;
import com.bumptech.glide.request.target.Target;
import com.bumptech.glide.test.BitmapSubject;
import com.bumptech.glide.test.ConcurrencyHelper;
import com.bumptech.glide.test.GlideApp;
Expand Down Expand Up @@ -78,7 +79,7 @@ public void submit_withDisabledMemoryCache_andResourceInActiveResources_loadsFro

verify(requestListener)
.onResourceReady(
any(Drawable.class),
anyDrawable(),
any(),
anyTarget(),
eq(DataSource.MEMORY_CACHE),
Expand Down Expand Up @@ -129,7 +130,7 @@ public void submit_withRequestClearedFromMemory_doesNotLoadFromMemory() {

verify(requestListener)
.onResourceReady(
any(Drawable.class),
anyDrawable(),
any(),
anyTarget(),
not(eq(DataSource.MEMORY_CACHE)),
Expand Down Expand Up @@ -157,7 +158,7 @@ public void submit_withPreviousRequestClearedFromMemory_completesFromDataDiskCac

verify(requestListener)
.onResourceReady(
any(Drawable.class),
anyDrawable(),
any(),
anyTarget(),
eq(DataSource.DATA_DISK_CACHE),
Expand Down Expand Up @@ -187,8 +188,13 @@ public void submit_withPreviousButNoLongerReferencedIdenticalRequest_completesFr
.listener(requestListener)
.submit(IMAGE_SIZE_PIXELS, IMAGE_SIZE_PIXELS));

verify(requestListener).onResourceReady(
any(Drawable.class), any(), anyTarget(), eq(DataSource.MEMORY_CACHE), anyBoolean());
verify(requestListener)
.onResourceReady(
anyDrawable(),
any(),
anyTarget(),
eq(DataSource.MEMORY_CACHE),
anyBoolean());
}

@Test
Expand Down Expand Up @@ -251,14 +257,15 @@ public void clearDiskCache_doesNotPreventFutureLoads()
.diskCacheStrategy(DiskCacheStrategy.DATA)
.submit(IMAGE_SIZE_PIXELS, IMAGE_SIZE_PIXELS));

verify(requestListener).onResourceReady(
any(Drawable.class), any(), anyTarget(), eq(DataSource.DATA_DISK_CACHE), anyBoolean());
verify(requestListener)
.onResourceReady(
anyDrawable(),
any(),
anyTarget(),
eq(DataSource.DATA_DISK_CACHE),
anyBoolean());
}

@SuppressWarnings("unchecked")
private static Target<Drawable> anyTarget() {
return (Target<Drawable>) any(Target.class);
}

private void clearMemoryCacheOnMainThread() throws InterruptedException {
concurrency.runOnMainThread(new Runnable() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,254 @@
package com.bumptech.glide;

import static com.bumptech.glide.test.Matchers.anyDrawable;
import static com.bumptech.glide.test.Matchers.anyTarget;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;

import android.content.Context;
import android.graphics.drawable.Drawable;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import android.widget.ImageView;
import com.bumptech.glide.load.DataSource;
import com.bumptech.glide.load.engine.executor.GlideExecutor;
import com.bumptech.glide.request.RequestListener;
import com.bumptech.glide.test.ConcurrencyHelper;
import com.bumptech.glide.test.GlideApp;
import com.bumptech.glide.test.ResourceIds;
import com.bumptech.glide.test.TearDownGlide;
import com.bumptech.glide.test.WaitModelLoader;
import com.bumptech.glide.test.WaitModelLoader.WaitModel;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

/**
* Tests the behaviors of Requests of all types.
*/
@RunWith(AndroidJUnit4.class)
public class RequestTest {
@Rule public TearDownGlide tearDownGlide = new TearDownGlide();
@Mock private RequestListener<Drawable> requestListener;
private ConcurrencyHelper concurrency = new ConcurrencyHelper();
private Context context;
private ImageView imageView;

@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
context = InstrumentationRegistry.getTargetContext();
imageView = new ImageView(context);
imageView.measure(100, 100);
imageView.layout(0, 0, 100, 100);

// Some emulators only have a single resize thread, so waiting on a latch will block them
// forever.
Glide.init(context,
new GlideBuilder().setResizeExecutor(GlideExecutor.newUnlimitedSourceExecutor()));
}

@Test
public void clear_withSingleRequest_nullsOutDrawableInView() {
concurrency.loadOnMainThread(
GlideApp.with(context)
.load(ResourceIds.raw.canonical),
imageView);
assertThat(imageView.getDrawable()).isNotNull();

concurrency.clearOnMainThread(imageView);
assertThat(imageView.getDrawable()).isNull();
}

@Test
public void clear_withRequestWithThumbnail_nullsOutDrawableInView() {
concurrency.loadOnMainThread(
GlideApp.with(context)
.load(ResourceIds.raw.canonical)
.thumbnail(
GlideApp.with(context)
.load(ResourceIds.raw.canonical)
.override(100, 100)),
imageView);
assertThat(imageView.getDrawable()).isNotNull();

concurrency.clearOnMainThread(imageView);
assertThat(imageView.getDrawable()).isNull();
}

@Test
public void onStop_withSingleRequest_doesNotNullOutDrawableInView() {
concurrency.loadOnMainThread(
GlideApp.with(context)
.load(ResourceIds.raw.canonical),
imageView);
assertThat(imageView.getDrawable()).isNotNull();

concurrency.runOnMainThread(new Runnable() {
@Override
public void run() {
GlideApp.with(context).onStop();
}
});
assertThat(imageView.getDrawable()).isNotNull();
}

@Test
public void onStop_withRequestWithThumbnail_doesNotNullOutDrawableInView() {
concurrency.loadOnMainThread(
GlideApp.with(context)
.load(ResourceIds.raw.canonical)
.thumbnail(
GlideApp.with(context)
.load(ResourceIds.raw.canonical)
.override(100, 100)),
imageView);
assertThat(imageView.getDrawable()).isNotNull();

concurrency.runOnMainThread(new Runnable() {
@Override
public void run() {
GlideApp.with(context).onStop();
}
});
assertThat(imageView.getDrawable()).isNotNull();
}

@Test
public void onStop_withSingleRequestInProgress_nullsOutDrawableInView() {
final WaitModel<Integer> model = WaitModelLoader.Factory.waitOn(ResourceIds.raw.canonical);
concurrency.runOnMainThread(
new Runnable() {
@Override
public void run() {
GlideApp.with(context)
.load(ResourceIds.raw.canonical)
.into(imageView);
}
});
concurrency.runOnMainThread(new Runnable() {
@Override
public void run() {
GlideApp.with(context).onStop();
}
});
assertThat(imageView.getDrawable()).isNull();
model.countDown();
}

@Test
public void onStop_withRequestWithThumbnailBothInProgress_nullsOutDrawableInView() {
final WaitModel<Integer> model = WaitModelLoader.Factory.waitOn(ResourceIds.raw.canonical);
concurrency.runOnMainThread(
new Runnable() {
@Override
public void run() {
GlideApp.with(context)
.load(model)
.thumbnail(
GlideApp.with(context)
.load(model)
.override(100, 100))
.into(imageView);

}
});

concurrency.runOnMainThread(new Runnable() {
@Override
public void run() {
GlideApp.with(context).onStop();
}
});
assertThat(imageView.getDrawable()).isNull();
model.countDown();
}

/** Tests #2555. */
@Test
public void onStop_withRequestWithOnlyFullInProgress_nullsOutDrawableInView() {
final WaitModel<Integer> mainModel = WaitModelLoader.Factory.waitOn(ResourceIds.raw.canonical);
concurrency.loadUntilFirstFinish(
GlideApp.with(context)
.load(mainModel)
.listener(requestListener)
.thumbnail(GlideApp.with(context)
.load(ResourceIds.raw.canonical)
.listener(requestListener)
.override(100, 100)),
imageView);

concurrency.runOnMainThread(new Runnable() {
@Override
public void run() {
GlideApp.with(context).onStop();
}
});

verify(requestListener, never())
.onResourceReady(
anyDrawable(),
any(),
anyTarget(),
eq(DataSource.DATA_DISK_CACHE),
anyBoolean());
verify(requestListener, never())
.onResourceReady(
anyDrawable(),
any(),
anyTarget(),
eq(DataSource.RESOURCE_DISK_CACHE),
anyBoolean());
assertThat(imageView.getDrawable()).isNull();
mainModel.countDown();
}

@Test
public void onStop_withRequestWithOnlyThumbnailInProgress_doesNotNullOutDrawableInView() {
final WaitModel<Integer> thumbModel = WaitModelLoader.Factory.waitOn(ResourceIds.raw.canonical);
concurrency.loadUntilFirstFinish(
GlideApp.with(context)
.load(ResourceIds.raw.canonical)
.listener(requestListener)
.thumbnail(GlideApp.with(context)
.load(thumbModel)
.listener(requestListener)
.override(100, 100)),
imageView);

concurrency.runOnMainThread(new Runnable() {
@Override
public void run() {
GlideApp.with(context).onStop();
}
});

verify(requestListener, never())
.onResourceReady(
anyDrawable(),
any(),
anyTarget(),
eq(DataSource.DATA_DISK_CACHE),
anyBoolean());
verify(requestListener, never())
.onResourceReady(
anyDrawable(),
any(),
anyTarget(),
eq(DataSource.RESOURCE_DISK_CACHE),
anyBoolean());

// Only requests that are running are paused in onStop. The full request should take priority
// over the thumbnail request. Therefore, if the full request is finished in onStop, it should
// not be cleared, even if the thumbnail request is still running.
assertThat(imageView.getDrawable()).isNotNull();
thumbModel.countDown();
}
}
Loading

0 comments on commit 9c82c42

Please sign in to comment.