Skip to content

Commit 9d10097

Browse files
committed
Avoid starting identical requests.
If a request is already in progress we should only cancel and restart it if the new request differs from the in progress request in some way. Prior to this change, we always cleared and restarted requests without checking to see if the request parameters had changed. Progress toward #2194.
1 parent 7004e59 commit 9d10097

File tree

9 files changed

+313
-9
lines changed

9 files changed

+313
-9
lines changed

library/src/main/java/com/bumptech/glide/RequestBuilder.java

+7-3
Original file line numberDiff line numberDiff line change
@@ -353,14 +353,18 @@ public <Y extends Target<TranscodeType>> Y into(@NonNull Y target) {
353353
throw new IllegalArgumentException("You must call #load() before calling #into()");
354354
}
355355

356-
Request previous = target.getRequest();
356+
requestOptions.lock();
357+
Request request = buildRequest(target);
357358

359+
Request previous = target.getRequest();
358360
if (previous != null) {
361+
if (request.isEquivalentTo(previous)) {
362+
request.recycle();
363+
return target;
364+
}
359365
requestManager.clear(target);
360366
}
361367

362-
requestOptions.lock();
363-
Request request = buildRequest(target);
364368
target.setRequest(request);
365369
requestManager.track(target, request);
366370

library/src/main/java/com/bumptech/glide/request/Request.java

+14
Original file line numberDiff line numberDiff line change
@@ -57,4 +57,18 @@ public interface Request {
5757
* Recycles the request object and releases its resources.
5858
*/
5959
void recycle();
60+
61+
/**
62+
* Returns {@code true} if this {@link Request} is equivalent to the given {@link Request} (has
63+
* all of the same options and sizes).
64+
*
65+
* <p>This method is identical to {@link #equals(Object)} except that it's specific to
66+
* {@link Request} subclasses. We do not use {@link #equals(Object)} directly because we track
67+
* {@link Request}s in collections like {@link java.util.Set} and it's perfectly legitimate to
68+
* have two different {@link Request} objects for two different
69+
* {@link com.bumptech.glide.request.target.Target}s (for example). Using a similar but different
70+
* method let's us selectively compare {@link Request} objects to each other when it's useful in
71+
* specific scenarios.
72+
*/
73+
boolean isEquivalentTo(Request other);
6074
}

library/src/main/java/com/bumptech/glide/request/RequestOptions.java

+56
Original file line numberDiff line numberDiff line change
@@ -1095,6 +1095,62 @@ public RequestOptions apply(RequestOptions other) {
10951095
return selfOrThrowIfLocked();
10961096
}
10971097

1098+
1099+
@Override
1100+
public boolean equals(Object o) {
1101+
if (o instanceof RequestOptions) {
1102+
RequestOptions other = (RequestOptions) o;
1103+
return Float.compare(other.sizeMultiplier, sizeMultiplier) == 0
1104+
&& errorId == other.errorId
1105+
&& Util.bothNullOrEqual(errorPlaceholder, other.errorPlaceholder)
1106+
&& placeholderId == other.placeholderId
1107+
&& Util.bothNullOrEqual(placeholderDrawable, other.placeholderDrawable)
1108+
&& fallbackId == other.fallbackId
1109+
&& Util.bothNullOrEqual(fallbackDrawable, other.fallbackDrawable)
1110+
&& isCacheable == other.isCacheable
1111+
&& overrideHeight == other.overrideHeight
1112+
&& overrideWidth == other.overrideWidth
1113+
&& isTransformationRequired == other.isTransformationRequired
1114+
&& isTransformationAllowed == other.isTransformationAllowed
1115+
&& useUnlimitedSourceGeneratorsPool == other.useUnlimitedSourceGeneratorsPool
1116+
&& onlyRetrieveFromCache == other.onlyRetrieveFromCache
1117+
&& diskCacheStrategy.equals(other.diskCacheStrategy)
1118+
&& priority == other.priority
1119+
&& options.equals(other.options)
1120+
&& transformations.equals(other.transformations)
1121+
&& resourceClass.equals(other.resourceClass)
1122+
&& Util.bothNullOrEqual(signature, other.signature)
1123+
&& Util.bothNullOrEqual(theme, other.theme);
1124+
}
1125+
return false;
1126+
}
1127+
1128+
@Override
1129+
public int hashCode() {
1130+
int hashCode = Util.hashCode(sizeMultiplier);
1131+
hashCode = Util.hashCode(errorId, hashCode);
1132+
hashCode = Util.hashCode(errorPlaceholder, hashCode);
1133+
hashCode = Util.hashCode(placeholderId, hashCode);
1134+
hashCode = Util.hashCode(placeholderDrawable, hashCode);
1135+
hashCode = Util.hashCode(fallbackId, hashCode);
1136+
hashCode = Util.hashCode(fallbackDrawable, hashCode);
1137+
hashCode = Util.hashCode(isCacheable, hashCode);
1138+
hashCode = Util.hashCode(overrideHeight, hashCode);
1139+
hashCode = Util.hashCode(overrideWidth, hashCode);
1140+
hashCode = Util.hashCode(isTransformationRequired, hashCode);
1141+
hashCode = Util.hashCode(isTransformationAllowed, hashCode);
1142+
hashCode = Util.hashCode(useUnlimitedSourceGeneratorsPool, hashCode);
1143+
hashCode = Util.hashCode(onlyRetrieveFromCache, hashCode);
1144+
hashCode = Util.hashCode(diskCacheStrategy, hashCode);
1145+
hashCode = Util.hashCode(priority, hashCode);
1146+
hashCode = Util.hashCode(options, hashCode);
1147+
hashCode = Util.hashCode(transformations, hashCode);
1148+
hashCode = Util.hashCode(resourceClass, hashCode);
1149+
hashCode = Util.hashCode(signature, hashCode);
1150+
hashCode = Util.hashCode(theme, hashCode);
1151+
return hashCode;
1152+
}
1153+
10981154
/**
10991155
* Throws if any further mutations are attempted.
11001156
*

library/src/main/java/com/bumptech/glide/request/SingleRequest.java

+15-1
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ private enum Status {
8080
PAUSED,
8181
}
8282

83-
private final String tag = String.valueOf(hashCode());
83+
private final String tag = String.valueOf(super.hashCode());
8484
private final StateVerifier stateVerifier = StateVerifier.newInstance();
8585

8686
private RequestCoordinator requestCoordinator;
@@ -551,6 +551,20 @@ private void onLoadFailed(GlideException e, int maxLogLevel) {
551551
}
552552
}
553553

554+
@Override
555+
public boolean isEquivalentTo(Request o) {
556+
if (o instanceof SingleRequest) {
557+
SingleRequest that = (SingleRequest) o;
558+
return overrideWidth == that.overrideWidth
559+
&& overrideHeight == that.overrideHeight
560+
&& model.equals(that.model)
561+
&& transcodeClass.equals(that.transcodeClass)
562+
&& requestOptions.equals(that.requestOptions)
563+
&& priority == that.priority;
564+
}
565+
return false;
566+
}
567+
554568
private void logV(String message) {
555569
Log.v(TAG, message + " this: " + tag);
556570
}

library/src/main/java/com/bumptech/glide/request/ThumbnailRequestCoordinator.java

+10
Original file line numberDiff line numberDiff line change
@@ -159,4 +159,14 @@ public void recycle() {
159159
full.recycle();
160160
thumb.recycle();
161161
}
162+
163+
@Override
164+
public boolean isEquivalentTo(Request o) {
165+
if (o instanceof ThumbnailRequestCoordinator) {
166+
ThumbnailRequestCoordinator that = (ThumbnailRequestCoordinator) o;
167+
return (full == null ? that.full == null : full.isEquivalentTo(that.full))
168+
&& (thumb == null ? that.thumb == null : thumb.isEquivalentTo(that.thumb));
169+
}
170+
return false;
171+
}
162172
}

library/src/main/java/com/bumptech/glide/util/Util.java

+31
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
* A collection of assorted utility classes.
1616
*/
1717
public final class Util {
18+
private static final int HASH_MULTIPLIER = 31;
19+
private static final int HASH_ACCUMULATOR = 17;
1820
private static final char[] HEX_CHAR_ARRAY = "0123456789abcdef".toCharArray();
1921
// 32 bytes from sha-256 -> 64 hex chars.
2022
private static final char[] SHA_256_CHARS = new char[64];
@@ -187,4 +189,33 @@ public static <T> List<T> getSnapshot(Collection<T> other) {
187189
public static boolean bothNullOrEqual(Object a, Object b) {
188190
return a == null ? b == null : a.equals(b);
189191
}
192+
193+
public static int hashCode(int value) {
194+
return hashCode(value, HASH_ACCUMULATOR);
195+
}
196+
197+
public static int hashCode(int value, int accumulator) {
198+
return accumulator * HASH_MULTIPLIER + value;
199+
}
200+
201+
public static int hashCode(float value) {
202+
return hashCode(value, HASH_ACCUMULATOR);
203+
}
204+
205+
public static int hashCode(float value, int accumulator) {
206+
return hashCode(Float.floatToIntBits(value), accumulator);
207+
}
208+
209+
public static int hashCode(Object object, int accumulator) {
210+
return hashCode(object == null ? 0 : object.hashCode(), accumulator);
211+
}
212+
213+
public static int hashCode(boolean value, int accumulator) {
214+
return hashCode(value ? 1 : 0, accumulator);
215+
}
216+
217+
public static int hashCode(boolean value) {
218+
return hashCode(value, HASH_ACCUMULATOR);
219+
}
220+
190221
}

library/src/test/java/com/bumptech/glide/request/RequestOptionsTest.java

+112-2
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,29 @@
22

33
import static com.google.common.truth.Truth.assertThat;
44

5+
import android.app.Application;
56
import android.graphics.Bitmap;
6-
7+
import android.graphics.Color;
8+
import android.graphics.drawable.ColorDrawable;
9+
import android.graphics.drawable.Drawable;
10+
import android.graphics.drawable.GradientDrawable;
11+
import com.bumptech.glide.Priority;
712
import com.bumptech.glide.load.MultiTransformation;
13+
import com.bumptech.glide.load.Option;
814
import com.bumptech.glide.load.Transformation;
15+
import com.bumptech.glide.load.engine.DiskCacheStrategy;
916
import com.bumptech.glide.load.resource.bitmap.CenterCrop;
1017
import com.bumptech.glide.load.resource.bitmap.CircleCrop;
11-
18+
import com.bumptech.glide.signature.ObjectKey;
19+
import com.bumptech.glide.util.Util;
20+
import com.google.common.testing.EqualsTester;
1221
import org.junit.Before;
1322
import org.junit.Test;
1423
import org.junit.runner.RunWith;
1524
import org.mockito.Mock;
1625
import org.mockito.MockitoAnnotations;
1726
import org.robolectric.RobolectricTestRunner;
27+
import org.robolectric.RuntimeEnvironment;
1828
import org.robolectric.annotation.Config;
1929

2030
@RunWith(RobolectricTestRunner.class)
@@ -23,11 +33,14 @@ public class RequestOptionsTest {
2333

2434
private RequestOptions options;
2535
@Mock private Transformation<Bitmap> transformation;
36+
private Application app;
2637

2738
@Before
2839
public void setUp() {
2940
MockitoAnnotations.initMocks(this);
3041
options = new RequestOptions();
42+
43+
app = RuntimeEnvironment.application;
3144
}
3245

3346
@Test
@@ -146,4 +159,101 @@ public void testApplyMultiTransform() {
146159
assertThat(options.getTransformations().get(Bitmap.class))
147160
.isInstanceOf(MultiTransformation.class);
148161
}
162+
163+
@Test
164+
public void testEqualsHashCode() {
165+
Drawable first = new ColorDrawable(Color.RED);
166+
Drawable second = new GradientDrawable();
167+
assertThat(first).isNotEqualTo(second);
168+
assertThat(Util.bothNullOrEqual(first, second)).isFalse();
169+
new EqualsTester()
170+
.addEqualityGroup(
171+
new RequestOptions().sizeMultiplier(.7f),
172+
new RequestOptions().sizeMultiplier(.7f))
173+
.addEqualityGroup(new RequestOptions().sizeMultiplier(0.8f))
174+
.addEqualityGroup(new RequestOptions().error(1), new RequestOptions().error(1))
175+
.addEqualityGroup(new RequestOptions().error(2))
176+
.addEqualityGroup(new RequestOptions().error(first), new RequestOptions().error(first))
177+
.addEqualityGroup(new RequestOptions().error(second))
178+
.addEqualityGroup(new RequestOptions().placeholder(1), new RequestOptions().placeholder(1))
179+
.addEqualityGroup(new RequestOptions().placeholder(2))
180+
.addEqualityGroup(
181+
new RequestOptions().placeholder(first),
182+
new RequestOptions().placeholder(first))
183+
.addEqualityGroup(new RequestOptions().placeholder(second))
184+
.addEqualityGroup(new RequestOptions().fallback(1), new RequestOptions().fallback(1))
185+
.addEqualityGroup(new RequestOptions().fallback(2))
186+
.addEqualityGroup(
187+
new RequestOptions().fallback(first),
188+
new RequestOptions().fallback(first))
189+
.addEqualityGroup(new RequestOptions().fallback(second))
190+
.addEqualityGroup(
191+
new RequestOptions().skipMemoryCache(true),
192+
new RequestOptions().skipMemoryCache(true))
193+
.addEqualityGroup(
194+
new RequestOptions(),
195+
new RequestOptions().skipMemoryCache(false),
196+
new RequestOptions().theme(null),
197+
new RequestOptions().onlyRetrieveFromCache(false),
198+
new RequestOptions().useUnlimitedSourceGeneratorsPool(false))
199+
.addEqualityGroup(
200+
new RequestOptions().override(100),
201+
new RequestOptions().override(100, 100))
202+
.addEqualityGroup(
203+
new RequestOptions().override(200),
204+
new RequestOptions().override(200, 200))
205+
.addEqualityGroup(
206+
new RequestOptions().override(100, 200),
207+
new RequestOptions().override(100, 200))
208+
.addEqualityGroup(
209+
new RequestOptions().override(200, 100),
210+
new RequestOptions().override(200, 100))
211+
.addEqualityGroup(
212+
new RequestOptions().centerCrop(),
213+
new RequestOptions().centerCrop())
214+
.addEqualityGroup(
215+
new RequestOptions().optionalCenterCrop(),
216+
new RequestOptions().optionalCenterCrop())
217+
.addEqualityGroup(new RequestOptions().fitCenter())
218+
.addEqualityGroup(new RequestOptions().circleCrop())
219+
.addEqualityGroup(new RequestOptions().centerInside())
220+
.addEqualityGroup(
221+
new RequestOptions().useUnlimitedSourceGeneratorsPool(true),
222+
new RequestOptions().useUnlimitedSourceGeneratorsPool(true))
223+
.addEqualityGroup(
224+
new RequestOptions().onlyRetrieveFromCache(true),
225+
new RequestOptions().onlyRetrieveFromCache(true))
226+
.addEqualityGroup(
227+
new RequestOptions().diskCacheStrategy(DiskCacheStrategy.ALL),
228+
new RequestOptions().diskCacheStrategy(DiskCacheStrategy.ALL))
229+
.addEqualityGroup(
230+
new RequestOptions().diskCacheStrategy(DiskCacheStrategy.NONE))
231+
.addEqualityGroup(
232+
new RequestOptions().priority(Priority.HIGH),
233+
new RequestOptions().priority(Priority.HIGH))
234+
.addEqualityGroup(
235+
new RequestOptions().priority(Priority.LOW))
236+
.addEqualityGroup(
237+
new RequestOptions().set(Option.<Boolean>memory("test"), true),
238+
new RequestOptions().set(Option.<Boolean>memory("test"), true))
239+
.addEqualityGroup(
240+
new RequestOptions().set(Option.<Boolean>memory("test"), false))
241+
.addEqualityGroup(
242+
new RequestOptions().set(Option.<Boolean>memory("test2"), true))
243+
.addEqualityGroup(
244+
new RequestOptions().decode(Integer.class),
245+
new RequestOptions().decode(Integer.class))
246+
.addEqualityGroup(
247+
new RequestOptions().decode(Float.class))
248+
.addEqualityGroup(
249+
new RequestOptions().signature(new ObjectKey("test")),
250+
new RequestOptions().signature(new ObjectKey("test")))
251+
.addEqualityGroup(
252+
new RequestOptions().signature(new ObjectKey("test2")))
253+
.addEqualityGroup(
254+
new RequestOptions().theme(app.getTheme()),
255+
new RequestOptions().theme(app.getTheme()))
256+
.testEquals();
257+
}
258+
149259
}

0 commit comments

Comments
 (0)