提交 f2285a83 编写于 作者: S Sam Judd

Add support for recursive thumbnail calls.

Fixes #149
上级 e7812093
......@@ -71,6 +71,7 @@ import static org.mockito.Matchers.eq;
import static org.mockito.Matchers.notNull;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
......@@ -569,6 +570,48 @@ public class GlideTest {
verify(target).onResourceReady(eq(expected), any(GlideAnimation.class));
}
@Test
public void testReceivesThumbnails() {
String full = mockUri("content://full");
String thumb = mockUri("content://thumb");
requestManager
.load(full)
.thumbnail(requestManager
.load(thumb))
.into(target);
verify(target, times(2)).onResourceReady(any(Drawable.class), any(GlideAnimation.class));
}
@Test
public void testReceivesRecursiveThumbnails() {
requestManager
.load(mockUri("content://first"))
.thumbnail(requestManager
.load(mockUri("content://second"))
.thumbnail(requestManager
.load(mockUri("content://third"))
.thumbnail(requestManager
.load(mockUri("content://fourth"))
)
)
)
.into(target);
verify(target, times(4)).onResourceReady(any(Drawable.class), any(GlideAnimation.class));
}
@Test
public void testReceivesRecursiveThumbnailWithPercentage() {
requestManager
.load(mockUri("content://first"))
.thumbnail(requestManager
.load(mockUri("content://second"))
.thumbnail(0.5f)
)
.into(target);
verify(target, times(3)).onResourceReady(any(Drawable.class), any(GlideAnimation.class));
}
@Test
public void testNullModelInGenericImageLoadDoesNotThrow() {
requestManager.load((Double) null).into(target);
......@@ -646,15 +689,15 @@ public class GlideTest {
Glide.get(getContext()).register(failModel, failResource, failFactory);
}
private void mockUri(String uriString) {
mockUri(Uri.parse(uriString), null);
private String mockUri(String uriString) {
return mockUri(Uri.parse(uriString), null);
}
private void mockUri(Uri uri) {
mockUri(uri, null);
private String mockUri(Uri uri) {
return mockUri(uri, null);
}
private void mockUri(Uri uri, InputStream is) {
private String mockUri(Uri uri, InputStream is) {
if (is == null) {
is = new ByteArrayInputStream(new byte[0]);
}
......@@ -667,6 +710,7 @@ public class GlideTest {
when(assetFileDescriptor.getParcelFileDescriptor()).thenReturn(parcelFileDescriptor);
shadowContentResolver.registerAssetFileDescriptor(uri, assetFileDescriptor);
return uri.toString();
}
private Context getContext() {
......
......@@ -792,9 +792,9 @@ public class GenericRequestTest {
}
@Test
public void testRequestListenerIsCalledWithIsFirstImageIfRequestCoordinatorReturnsNoRequestComplete() {
public void testRequestListenerIsCalledWithIsFirstImageIfRequestCoordinatorReturnsNoResourceSet() {
GenericRequest request = harness.getRequest();
when(harness.requestCoordinator.isAnyRequestComplete()).thenReturn(false);
when(harness.requestCoordinator.isAnyResourceSet()).thenReturn(false);
request.onResourceReady(harness.resource);
verify(harness.requestListener).onResourceReady(eq(harness.result), any(Number.class), any(Target.class),
......@@ -802,9 +802,9 @@ public class GenericRequestTest {
}
@Test
public void testRequestListenerIsCalledWithNotIsFirstRequestIfRequestCoordinatorReturnsARequestComplete() {
public void testRequestListenerIsCalledWithNotIsFirstRequestIfRequestCoordinatorReturnsResourceSet() {
GenericRequest request = harness.getRequest();
when(harness.requestCoordinator.isAnyRequestComplete()).thenReturn(true);
when(harness.requestCoordinator.isAnyResourceSet()).thenReturn(true);
request.onResourceReady(harness.resource);
verify(harness.requestListener).onResourceReady(eq(harness.result), any(Number.class), any(Target.class),
......
......@@ -6,6 +6,7 @@ import org.mockito.InOrder;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
......@@ -16,11 +17,13 @@ public class ThumbnailRequestCoordinatorTest {
private Request full;
private Request thumb;
private ThumbnailRequestCoordinator coordinator;
private RequestCoordinator parent;
@Before
public void setUp() {
full = mock(Request.class);
thumb = mock(Request.class);
parent = mock(RequestCoordinator.class);
coordinator = new ThumbnailRequestCoordinator();
coordinator.setRequests(full, thumb);
}
......@@ -75,22 +78,6 @@ public class ThumbnailRequestCoordinatorTest {
verify(thumb, never()).begin();
}
@Test
public void testDoesNotAllowThumbToSetPlaceholder() {
assertFalse(coordinator.canNotifyStatusChanged(thumb));
}
@Test
public void testAllowsFullToSetPlaceholder() {
assertTrue(coordinator.canNotifyStatusChanged(full));
}
@Test
public void testDoesNotAllowFullToSetPlaceholderIfThumbComplete() {
when(thumb.isComplete()).thenReturn(true);
assertFalse(coordinator.canNotifyStatusChanged(full));
}
@Test
public void testCallsClearOnRequestsWhenCleared() {
coordinator.clear();
......@@ -119,4 +106,161 @@ public class ThumbnailRequestCoordinatorTest {
verify(thumb).pause();
}
@Test
public void testCanSetImageReturnsTrueForFullRequestIfCoordinatorIsNull() {
coordinator = new ThumbnailRequestCoordinator();
coordinator.setRequests(full, thumb);
assertTrue(coordinator.canSetImage(full));
}
@Test
public void testCanSetImageReturnsTrueForFullRequestIfParentAllowsSetImage() {
coordinator = new ThumbnailRequestCoordinator(parent);
coordinator.setRequests(full, thumb);
when(parent.canSetImage(eq(coordinator))).thenReturn(true);
assertTrue(coordinator.canSetImage(full));
}
@Test
public void testCanSetImageReturnsFalseForFullRequestIfParentDoesNotAllowSetImage() {
coordinator = new ThumbnailRequestCoordinator(parent);
coordinator.setRequests(full, thumb);
when(parent.canSetImage(eq(coordinator))).thenReturn(false);
assertFalse(coordinator.canSetImage(full));
}
@Test
public void testCanSetImageReturnsTrueForThumbRequestIfParentIsNullAndFullDoesNotHaveResourceSet() {
when(full.isResourceSet()).thenReturn(false);
assertTrue(coordinator.canSetImage(thumb));
}
@Test
public void testCanSetImageReturnsFalseForThumbRequestIfParentIsNullAndFullHasResourceSet() {
when(full.isResourceSet()).thenReturn(true);
assertFalse(coordinator.canSetImage(thumb));
}
@Test
public void testCanSetImageReturnsFalseForThumbRequestIfParentDoesNotAllowSetImageAndFullDoesNotHaveResourceSet() {
coordinator = new ThumbnailRequestCoordinator(parent);
coordinator.setRequests(full, thumb);
when(parent.canSetImage(eq(coordinator))).thenReturn(false);
when(full.isResourceSet()).thenReturn(false);
assertFalse(coordinator.canSetImage(thumb));
}
@Test
public void testCanNotifyStatusChangedIfFullAndNoRequestsAreComplete() {
assertTrue(coordinator.canNotifyStatusChanged(full));
}
@Test
public void testCanNotNotifyStatusChangedIfThumb() {
assertFalse(coordinator.canNotifyStatusChanged(thumb));
}
@Test
public void testCanNotNotifyStatusChangedIfFullHasResourceSet() {
when(full.isResourceSet()).thenReturn(true);
assertFalse(coordinator.canNotifyStatusChanged(full));
}
@Test
public void testCanNotNotifyStatusChangedIfThumbHasResourceSet() {
when(thumb.isResourceSet()).thenReturn(true);
assertFalse(coordinator.canNotifyStatusChanged(full));
}
@Test
public void testCanNotNotifyStatusChangedIfParentHasResourceSet() {
coordinator = new ThumbnailRequestCoordinator(parent);
coordinator.setRequests(full, thumb);
when(parent.isAnyResourceSet()).thenReturn(true);
assertFalse(coordinator.canNotifyStatusChanged(full));
}
@Test
public void testCanNotifyStatusChangedIfParentAllowsNotify() {
coordinator = new ThumbnailRequestCoordinator(parent);
coordinator.setRequests(full, thumb);
when(parent.canNotifyStatusChanged(eq(coordinator))).thenReturn(true);
assertTrue(coordinator.canNotifyStatusChanged(full));
}
@Test
public void testCanNotNotifyStatusChangedIfParentDoesNotAllowNotify() {
coordinator = new ThumbnailRequestCoordinator(parent);
coordinator.setRequests(full, thumb);
when(parent.canNotifyStatusChanged(eq(coordinator))).thenReturn(false);
assertFalse(coordinator.canNotifyStatusChanged(full));
}
@Test
public void testIsAnyResourceSetIsFalseIfNeitherRequestHasResourceSet() {
when(full.isResourceSet()).thenReturn(false);
when(thumb.isResourceSet()).thenReturn(false);
assertFalse(coordinator.isAnyResourceSet());
}
@Test
public void testIsAnyResourceSetIsTrueIfFullHasResourceSet() {
when(full.isResourceSet()).thenReturn(true);
when(thumb.isResourceSet()).thenReturn(false);
assertTrue(coordinator.isAnyResourceSet());
}
@Test
public void testIsAnyResourceSetIsTrueIfThumbHasResourceSet() {
when(full.isResourceSet()).thenReturn(false);
when(thumb.isResourceSet()).thenReturn(true);
assertTrue(coordinator.isAnyResourceSet());
}
@Test
public void testIsAnyResourceSetIsTrueIfParentIsNonNullAndParentHasResourceSet() {
coordinator = new ThumbnailRequestCoordinator(parent);
coordinator.setRequests(full, thumb);
when(parent.isAnyResourceSet()).thenReturn(true);
when(full.isResourceSet()).thenReturn(false);
when(thumb.isResourceSet()).thenReturn(false);
assertTrue(coordinator.isAnyResourceSet());
}
@Test
public void testIsNotCompleteIfNeitherRequestIsComplete() {
assertFalse(coordinator.isComplete());
}
@Test
public void testIsCompleteIfFullIsComplete() {
when(full.isComplete()).thenReturn(true);
assertTrue(coordinator.isComplete());
}
@Test
public void testIsCompleteIfThumbIsComplete() {
when(thumb.isComplete()).thenReturn(true);
assertTrue(coordinator.isComplete());
}
@Test
public void testIsResourceSetIsFalseIfNeitherRequestHasResourceSet() {
assertFalse(coordinator.isResourceSet());
}
@Test
public void testIsResourceSetIsTrueIfFullRequestHasResourceSet() {
when(full.isResourceSet()).thenReturn(true);
assertTrue(coordinator.isResourceSet());
}
@Test
public void testIsResourceSetIsTrueIfThumbRequestHasResourceSet() {
when(thumb.isResourceSet()).thenReturn(true);
assertTrue(coordinator.isResourceSet());
}
}
......@@ -12,6 +12,7 @@ import com.bumptech.glide.request.animation.GlideAnimation;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InOrder;
import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
......@@ -32,6 +33,7 @@ import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
......@@ -146,6 +148,35 @@ public class ViewTargetTest {
verify(cb).onSizeReady(eq(width), eq(height));
}
@Test
public void testSizeCallbacksAreCalledInOrderPreDraw() {
SizeReadyCallback[] cbs = new SizeReadyCallback[25];
for (int i = 0; i < cbs.length; i++) {
cbs[i] = mock(SizeReadyCallback.class);
target.getSize(cbs[i]);
}
int width = 100, height = 111;
SizedShadowView shadowView = Robolectric.shadowOf_(view);
shadowView.setWidth(width);
shadowView.setHeight(height);
PreDrawShadowViewTreeObserver shadowObserver = Robolectric.shadowOf_(view.getViewTreeObserver());
shadowObserver.fireOnPreDrawListeners();
InOrder order = inOrder((Object[]) cbs);
for (SizeReadyCallback cb : cbs) {
order.verify(cb).onSizeReady(eq(width), eq(height));
}
}
@Test(expected = IllegalArgumentException.class)
public void testThrowsIfCallbackIsQueuedTwice() {
SizeReadyCallback cb = mock(SizeReadyCallback.class);
target.getSize(cb);
target.getSize(cb);
}
@Test
public void testSizeCallbackIsNotCalledPreDrawIfNoDimensSetOnPreDraw() {
SizeReadyCallback cb = mock(SizeReadyCallback.class);
......
......@@ -54,7 +54,8 @@ public class GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeT
private final Class<TranscodeType> transcodeClass;
private final Glide glide;
private final RequestTracker requestTracker;
private Lifecycle lifecycle;
private final Lifecycle lifecycle;
private int placeholderId;
private int errorId;
private RequestListener<ModelType, TranscodeType> requestListener;
......@@ -94,21 +95,14 @@ public class GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeT
/**
* Loads and displays the resource retrieved by the given thumbnail request if it finishes before this request.
* Best used for loading thumbnail resources that are smaller and will be loaded more quickly than the fullsize
* Best used for loading thumbnail resources that are smaller and will be loaded more quickly than the full size
* resource. There are no guarantees about the order in which the requests will actually finish. However, if the
* thumb request completes after the full request, the thumb resource will never replace the full resource.
*
* @see #thumbnail(float)
*
* <p>
* Note - Any options on the main request will not be passed on to the thumbnail request. For example, if
* you want an animation to occur when either the full resource loads or the thumbnail loads, you need to call
* {@link #animate(int)} on both the thumb and the full request. For a simpler thumbnail option, see
* {@link #thumbnail(float)}.
* </p>
*
* <p>
* Only the thumbnail call on the main request will be obeyed.
* Recursive calls to thumbnail are supported.
* </p>
*
* @param thumbnailRequest The request to use to load the thumbnail.
......@@ -141,7 +135,7 @@ public class GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeT
* </p>
*
* <p>
* Only the thumbnail call on the main request will be obeyed.
* Recursive calls to thumbnail are supported.
* </p>
*
* @param sizeMultiplier The multiplier to apply to the {@link Target}'s dimensions when loading the thumbnail.
......@@ -613,17 +607,28 @@ public class GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeT
// To be implemented by subclasses when possible.
}
private Request buildRequest(Target<TranscodeType> target) {
final Request result;
private Priority getThumbnailPriority() {
final Priority result;
if (priority == Priority.LOW) {
result = Priority.NORMAL;
} else if (priority == Priority.NORMAL) {
result = Priority.HIGH;
} else {
result = Priority.IMMEDIATE;
}
return result;
}
private Request buildRequest(Target<TranscodeType> target) {
if (priority == null) {
priority = Priority.NORMAL;
}
return buildRequestRecursive(target, null);
}
private Request buildRequestRecursive(Target<TranscodeType> target, ThumbnailRequestCoordinator parentCoordinator) {
if (thumbnailRequestBuilder != null) {
ThumbnailRequestCoordinator requestCoordinator = new ThumbnailRequestCoordinator();
Request fullRequest = buildRequest(target, sizeMultiplier, priority, requestCoordinator);
// Recursive case: contains a potentially recursive thumbnail request builder.
if (thumbnailRequestBuilder.animationFactory.equals(NoAnimation.getFactory())) {
thumbnailRequestBuilder.animationFactory = animationFactory;
}
......@@ -636,48 +641,31 @@ public class GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeT
thumbnailRequestBuilder.priority = getThumbnailPriority();
}
Request thumbnailRequest = thumbnailRequestBuilder.buildRequest(target,
thumbnailRequestBuilder.sizeMultiplier, thumbnailRequestBuilder.priority, requestCoordinator);
requestCoordinator.setRequests(fullRequest, thumbnailRequest);
result = requestCoordinator;
ThumbnailRequestCoordinator coordinator = new ThumbnailRequestCoordinator(parentCoordinator);
Request fullRequest = obtainRequest(target, sizeMultiplier, priority, coordinator);
// Recursively generate thumbnail requests.
Request thumbRequest = thumbnailRequestBuilder.buildRequestRecursive(target, coordinator);
coordinator.setRequests(fullRequest, thumbRequest);
return coordinator;
} else if (thumbSizeMultiplier != null) {
ThumbnailRequestCoordinator requestCoordinator = new ThumbnailRequestCoordinator();
Request fullRequest = buildRequest(target, sizeMultiplier, priority, requestCoordinator);
Request thumbnailRequest = buildRequest(target, thumbSizeMultiplier, getThumbnailPriority(),
requestCoordinator);
requestCoordinator.setRequests(fullRequest, thumbnailRequest);
result = requestCoordinator;
// Base case: thumbnail multiplier generates a thumbnail request, but cannot recurse.
ThumbnailRequestCoordinator coordinator = new ThumbnailRequestCoordinator(parentCoordinator);
Request fullRequest = obtainRequest(target, sizeMultiplier, priority, coordinator);
Request thumbnailRequest = obtainRequest(target, thumbSizeMultiplier, getThumbnailPriority(), coordinator);
coordinator.setRequests(fullRequest, thumbnailRequest);
return coordinator;
} else {
result = buildRequest(target, sizeMultiplier, priority, null);
// Base case: no thumbnail.
return obtainRequest(target, sizeMultiplier, priority, parentCoordinator);
}
return result;
}
private Priority getThumbnailPriority() {
final Priority result;
if (priority == Priority.LOW) {
result = Priority.NORMAL;
} else if (priority == Priority.NORMAL) {
result = Priority.HIGH;
} else {
result = Priority.IMMEDIATE;
}
return result;
}
private Request buildRequest(Target<TranscodeType> target, float sizeMultiplier, Priority priority,
private <Z> Request obtainRequest(Target<TranscodeType> target, float sizeMultiplier, Priority priority,
RequestCoordinator requestCoordinator) {
if (model == null) {
return buildRequestForDataType(target, loadProvider, sizeMultiplier, priority, null);
} else {
return buildRequestForDataType(target, loadProvider, sizeMultiplier, priority, requestCoordinator);
requestCoordinator = null;
}
}
private <Z> Request buildRequestForDataType(Target<TranscodeType> target,
LoadProvider<ModelType, Z, ResourceType, TranscodeType> loadProvider, float sizeMultiplier,
Priority priority, RequestCoordinator requestCoordinator) {
return GenericRequest.obtain(
loadProvider,
model,
......
......@@ -143,7 +143,8 @@ class SourceResourceRunner<T, Z, R> implements Runnable, Prioritized {
if (decoded == null) {
decoded = decodeFromSource();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Decoded from source in " + (SystemClock.currentThreadTimeMillis() - start) + " cache");
Log.v(TAG, "Decoded from source in " + (SystemClock.currentThreadTimeMillis() - start) + " key: "
+ key);
start = SystemClock.currentThreadTimeMillis();
}
}
......@@ -155,7 +156,7 @@ class SourceResourceRunner<T, Z, R> implements Runnable, Prioritized {
decoded.recycle();
}
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "transformed in " + (SystemClock.currentThreadTimeMillis() - start));
Log.v(TAG, "transformed in " + (SystemClock.currentThreadTimeMillis() - start) + " key: " + key);
}
}
......@@ -167,7 +168,7 @@ class SourceResourceRunner<T, Z, R> implements Runnable, Prioritized {
start = SystemClock.currentThreadTimeMillis();
transcoded = transcoder.transcode(transformed);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.d(TAG, "transcoded in " + (SystemClock.currentThreadTimeMillis() - start));
Log.d(TAG, "transcoded in " + (SystemClock.currentThreadTimeMillis() - start) + " key: " + key);
}
}
return transcoded;
......
......@@ -338,6 +338,17 @@ public final class GenericRequest<A, T, Z, R> implements Request, SizeReadyCallb
return status == Status.COMPLETE;
}
/**
* {@inheritDoc}
*/
@Override
public boolean isResourceSet() {
return isComplete();
}
/**
* {@inheritDoc}
*/
@Override
public boolean isCancelled() {
return status == Status.CANCELLED;
......@@ -428,7 +439,7 @@ public final class GenericRequest<A, T, Z, R> implements Request, SizeReadyCallb
}
private boolean isFirstReadyResource() {
return requestCoordinator == null || !requestCoordinator.isAnyRequestComplete();
return requestCoordinator == null || !requestCoordinator.isAnyResourceSet();
}
/**
......
......@@ -36,6 +36,12 @@ public interface Request {
*/
public boolean isComplete();
/**
* Returns true if a non-placeholder resource is set. For Requests that load more than one resource, isResourceSet
* may return true even if {@link #isComplete()}} returns false.
*/
public boolean isResourceSet();
/**
* Returns true if the request has been cancelled.
*/
......
......@@ -24,5 +24,5 @@ public interface RequestCoordinator {
*
* @see Request#isComplete()
*/
public boolean isAnyRequestComplete();
public boolean isAnyResourceSet();
}
......@@ -7,6 +7,15 @@ package com.bumptech.glide.request;
public class ThumbnailRequestCoordinator implements RequestCoordinator, Request {
private Request full;
private Request thumb;
private RequestCoordinator coordinator;
public ThumbnailRequestCoordinator() {
this(null);
}
public ThumbnailRequestCoordinator(RequestCoordinator coordinator) {
this.coordinator = coordinator;
}
public void setRequests(Request full, Request thumb) {
this.full = full;
......@@ -14,14 +23,19 @@ public class ThumbnailRequestCoordinator implements RequestCoordinator, Request
}
/**
*
* Returns true if the request is either the request loading the fullsize image or if the request loading the
* fullsize image has not yet completed.
* full size image has not yet completed.
*
* @param request {@inheritDoc}
*/
@Override
public boolean canSetImage(Request request) {
return request == full || !full.isComplete();
return parentCanSetImage() && (request == full || !full.isResourceSet());
}
private boolean parentCanSetImage() {
return coordinator == null || coordinator.canSetImage(this);
}
/**
......@@ -32,16 +46,20 @@ public class ThumbnailRequestCoordinator implements RequestCoordinator, Request
*/
@Override
public boolean canNotifyStatusChanged(Request request) {
return request == full && !isAnyRequestComplete();
return parentCanNotifyStatusChanged() && (request == full && !isAnyResourceSet());
}
private boolean parentCanNotifyStatusChanged() {
return coordinator == null || coordinator.canNotifyStatusChanged(this);
}
/**
* Returns true if either the full request has completed successfully or the thumb request has completed
* successfully.
*/
@Override
public boolean isAnyRequestComplete() {
return full.isComplete() || thumb.isComplete();
public boolean isAnyResourceSet() {
return parentIsAnyResourceSet() || isResourceSet();
}
private boolean parentIsAnyResourceSet() {
return coordinator != null && coordinator.isAnyResourceSet();
}
/**
......@@ -90,7 +108,12 @@ public class ThumbnailRequestCoordinator implements RequestCoordinator, Request
*/
@Override
public boolean isComplete() {
return full.isComplete();
return full.isComplete() || thumb.isComplete();
}
@Override
public boolean isResourceSet() {
return full.isResourceSet() || thumb.isResourceSet();
}
@Override
......
......@@ -7,12 +7,11 @@ import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.WindowManager;
import com.bumptech.glide.request.Request;
import java.lang.ref.WeakReference;
import java.util.HashSet;
import java.util.Set;
import java.util.ArrayList;
import java.util.List;
/**
* A base {@link Target} for loading {@link android.graphics.Bitmap}s into {@link View}s that provides default
......@@ -112,7 +111,7 @@ public abstract class ViewTarget<T extends View, Z> extends BaseTarget<Z> {
private static class SizeDeterminer {
private final View view;
private Set<SizeReadyCallback> cbs = new HashSet<SizeReadyCallback>();
private List<SizeReadyCallback> cbs = new ArrayList<SizeReadyCallback>();
private SizeDeterminerLayoutListener layoutListener;
public SizeDeterminer(View view) {
......@@ -173,6 +172,9 @@ public abstract class ViewTarget<T extends View, Z> extends BaseTarget<Z> {
}
cb.onSizeReady(width, height);
} else {
if (cbs.contains(cb)) {
throw new IllegalArgumentException("Cannot add a callback twice");
}
cbs.add(cb);
final ViewTreeObserver observer = view.getViewTreeObserver();
layoutListener = new SizeDeterminerLayoutListener(this);
......
......@@ -166,7 +166,7 @@ public class FlickrPhotoGrid extends Fragment implements PhotoViewer {
DrawableRequestBuilder<Photo> request = Glide.with(FlickrPhotoGrid.this)
.load(current)
.centerCrop()
.animate(R.anim.fade_in);
.crossFade(R.anim.fade_in, 150);
if (thumbnail) {
request.thumbnail(Glide.with(FlickrPhotoGrid.this)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册