blob: 13319d7395987665265ccd7d67929e5cb73b599f [file] [log] [blame]
package com.bumptech.glide;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.view.animation.Animation;
import android.widget.ImageView;
import com.bumptech.glide.load.Encoder;
import com.bumptech.glide.load.Key;
import com.bumptech.glide.load.MultiTransformation;
import com.bumptech.glide.load.ResourceDecoder;
import com.bumptech.glide.load.ResourceEncoder;
import com.bumptech.glide.load.Transformation;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.load.resource.UnitTransformation;
import com.bumptech.glide.load.resource.transcode.ResourceTranscoder;
import com.bumptech.glide.manager.Lifecycle;
import com.bumptech.glide.manager.RequestTracker;
import com.bumptech.glide.provider.ChildLoadProvider;
import com.bumptech.glide.provider.LoadProvider;
import com.bumptech.glide.request.FutureTarget;
import com.bumptech.glide.request.GenericRequest;
import com.bumptech.glide.request.Request;
import com.bumptech.glide.request.RequestCoordinator;
import com.bumptech.glide.request.RequestFutureTarget;
import com.bumptech.glide.request.RequestListener;
import com.bumptech.glide.request.ThumbnailRequestCoordinator;
import com.bumptech.glide.request.animation.GlideAnimationFactory;
import com.bumptech.glide.request.animation.NoAnimation;
import com.bumptech.glide.request.animation.ViewAnimationFactory;
import com.bumptech.glide.request.animation.ViewPropertyAnimation;
import com.bumptech.glide.request.animation.ViewPropertyAnimationFactory;
import com.bumptech.glide.request.target.PreloadTarget;
import com.bumptech.glide.request.target.Target;
import com.bumptech.glide.signature.EmptySignature;
import com.bumptech.glide.util.Util;
import java.io.File;
/**
* A generic class that can handle setting options and staring loads for generic resource types.
*
* @param <ModelType> The type of model representing the resource.
* @param <DataType> The data type that the resource {@link com.bumptech.glide.load.model.ModelLoader} will provide that
* can be decoded by the {@link com.bumptech.glide.load.ResourceDecoder}.
* @param <ResourceType> The type of the resource that will be loaded.
* @param <TranscodeType> The type of resource the decoded resource will be transcoded to.
*/
public class GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> implements Cloneable {
protected final Class<ModelType> modelClass;
protected final Context context;
protected final Glide glide;
protected final Class<TranscodeType> transcodeClass;
protected final RequestTracker requestTracker;
protected final Lifecycle lifecycle;
private ChildLoadProvider<ModelType, DataType, ResourceType, TranscodeType> loadProvider;
private ModelType model;
private Key signature = EmptySignature.obtain();
// model may occasionally be null, so to enforce that load() was called, set a boolean rather than relying on model
// not to be null.
private boolean isModelSet;
private int placeholderId;
private int errorId;
private RequestListener<? super ModelType, TranscodeType> requestListener;
private Float thumbSizeMultiplier;
private GenericRequestBuilder<?, ?, ?, TranscodeType> thumbnailRequestBuilder;
private Float sizeMultiplier = 1f;
private Drawable placeholderDrawable;
private Drawable errorPlaceholder;
private Priority priority = null;
private boolean isCacheable = true;
private GlideAnimationFactory<TranscodeType> animationFactory = NoAnimation.getFactory();
private int overrideHeight = -1;
private int overrideWidth = -1;
private DiskCacheStrategy diskCacheStrategy = DiskCacheStrategy.RESULT;
private Transformation<ResourceType> transformation = UnitTransformation.get();
private boolean isTransformationSet;
GenericRequestBuilder(LoadProvider<ModelType, DataType, ResourceType, TranscodeType> loadProvider,
Class<TranscodeType> transcodeClass, GenericRequestBuilder<ModelType, ?, ?, ?> other) {
this(other.context, other.modelClass, loadProvider, transcodeClass, other.glide, other.requestTracker,
other.lifecycle);
this.model = other.model;
this.isModelSet = other.isModelSet;
this.signature = other.signature;
this.diskCacheStrategy = other.diskCacheStrategy;
this.isCacheable = other.isCacheable;
}
GenericRequestBuilder(Context context, Class<ModelType> modelClass,
LoadProvider<ModelType, DataType, ResourceType, TranscodeType> loadProvider,
Class<TranscodeType> transcodeClass, Glide glide, RequestTracker requestTracker, Lifecycle lifecycle) {
this.context = context;
this.modelClass = modelClass;
this.transcodeClass = transcodeClass;
this.glide = glide;
this.requestTracker = requestTracker;
this.lifecycle = lifecycle;
this.loadProvider = loadProvider != null
? new ChildLoadProvider<ModelType, DataType, ResourceType, TranscodeType>(loadProvider) : null;
if (context == null) {
throw new NullPointerException("Context can't be null");
}
if (modelClass != null && loadProvider == null) {
throw new NullPointerException("LoadProvider must not be null");
}
}
/**
* 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 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>
* Recursive calls to thumbnail are supported.
* </p>
*
* @param thumbnailRequest The request to use to load the thumbnail.
* @return This request builder.
*/
public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> thumbnail(
GenericRequestBuilder<?, ?, ?, TranscodeType> thumbnailRequest) {
this.thumbnailRequestBuilder = thumbnailRequest;
return this;
}
/**
* Loads a resource in an identical manner to this request except with the dimensions of the target multiplied
* by the given size multiplier. If the thumbnail load completes before the fullsize load, the thumbnail will
* be shown. If the thumbnail load completes afer the fullsize load, the thumbnail will not be shown.
*
* <p>
* Note - The thumbnail resource will be smaller than the size requested so the target (or {@link ImageView})
* must be able to scale the thumbnail appropriately. See {@link android.widget.ImageView.ScaleType}.
* </p>
*
* <p>
* Almost all options will be copied from the original load, including the
* {@link com.bumptech.glide.load.model.ModelLoader}, {@link com.bumptech.glide.load.ResourceDecoder}, and
* {@link Transformation}s. However, {@link #placeholder(int)} and {@link #error(int)},
* and {@link #listener(RequestListener)} will only be used on the fullsize load and will not be copied for
* the thumbnail load.
* </p>
*
* <p>
* Recursive calls to thumbnail are supported.
* </p>
*
* @param sizeMultiplier The multiplier to apply to the {@link Target}'s dimensions when loading the thumbnail.
* @return This request builder.
*/
public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> thumbnail(
float sizeMultiplier) {
if (sizeMultiplier < 0f || sizeMultiplier > 1f) {
throw new IllegalArgumentException("sizeMultiplier must be between 0 and 1");
}
this.thumbSizeMultiplier = sizeMultiplier;
return this;
}
/**
* Applies a multiplier to the {@link Target}'s size before loading the resource. Useful for loading thumbnails
* or trying to avoid loading huge resources (particularly {@link android.graphics.Bitmap}s on devices with overly
* dense screens.
*
* @param sizeMultiplier The multiplier to apply to the {@link Target}'s dimensions when loading the resource.
* @return This request builder.
*/
public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> sizeMultiplier(
float sizeMultiplier) {
if (sizeMultiplier < 0f || sizeMultiplier > 1f) {
throw new IllegalArgumentException("sizeMultiplier must be between 0 and 1");
}
this.sizeMultiplier = sizeMultiplier;
return this;
}
/**
* Sets the {@link com.bumptech.glide.load.ResourceDecoder} to use to load the resource from the original data.
* By default, this decoder will only be used if the final transformed resource is not in the disk cache.
*
* @see #cacheDecoder(com.bumptech.glide.load.ResourceDecoder)
* @see com.bumptech.glide.load.engine.DiskCacheStrategy
*
* @param decoder The {@link com.bumptech.glide.load.ResourceDecoder} to use to decode the resource.
* @return This request builder.
*/
public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> decoder(
ResourceDecoder<DataType, ResourceType> decoder) {
// loadProvider will be null if model is null, in which case we're not going to load anything so it's ok to
// ignore the decoder.
if (loadProvider != null) {
loadProvider.setSourceDecoder(decoder);
}
return this;
}
/**
* Sets the {@link com.bumptech.glide.load.ResourceDecoder} to use to load the resource from the disk cache. By
* default, this decoder will only be used if the final transformed resource is already in the disk cache.
*
* @see #decoder(com.bumptech.glide.load.ResourceDecoder)
* @see com.bumptech.glide.load.engine.DiskCacheStrategy
*
* @param cacheDecoder The decoder to use.
* @return This request builder.
*/
public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> cacheDecoder(
ResourceDecoder<File, ResourceType> cacheDecoder) {
// loadProvider will be null if model is null, in which case we're not going to load anything so it's ok to
// ignore the decoder.
if (loadProvider != null) {
loadProvider.setCacheDecoder(cacheDecoder);
}
return this;
}
/**
* Sets the source encoder to use to encode the data retrieved by this request directly into cache. The returned
* resource will then be decoded from the cached data.
*
* @see com.bumptech.glide.load.engine.DiskCacheStrategy
*
* @param sourceEncoder The encoder to use.
* @return This request builder.
*/
public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> sourceEncoder(
Encoder<DataType> sourceEncoder) {
if (loadProvider != null) {
loadProvider.setSourceEncoder(sourceEncoder);
}
return this;
}
/**
* Sets the {@link com.bumptech.glide.load.engine.DiskCacheStrategy} to use for this load. Defaults to
* {@link com.bumptech.glide.load.engine.DiskCacheStrategy#RESULT}.
*
* <p>
* For most applications {@link com.bumptech.glide.load.engine.DiskCacheStrategy#RESULT} is ideal.
* Applications that use the same resource multiple times in multiple sizes and are willing to trade off some
* speed and disk space in return for lower bandwidth usage may want to consider using
* {@link com.bumptech.glide.load.engine.DiskCacheStrategy#SOURCE} or
* {@link com.bumptech.glide.load.engine.DiskCacheStrategy#RESULT}. Any download only operations should
* typically use {@link com.bumptech.glide.load.engine.DiskCacheStrategy#SOURCE}.
* </p>
*
* @param strategy The strategy to use.
* @return This request builder.
*/
public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> diskCacheStrategy(
DiskCacheStrategy strategy) {
this.diskCacheStrategy = strategy;
return this;
}
/**
* Sets the {@link com.bumptech.glide.load.Encoder} to use to encode the original data directly to cache. Will only
* be used if the original data is not already in cache and if the
* {@link com.bumptech.glide.load.engine.DiskCacheStrategy} is set to
* {@link com.bumptech.glide.load.engine.DiskCacheStrategy#SOURCE} or
* {@link com.bumptech.glide.load.engine.DiskCacheStrategy#ALL}.
*
* @see #sourceEncoder(com.bumptech.glide.load.Encoder)
* @see com.bumptech.glide.load.engine.DiskCacheStrategy
*
* @param encoder The encoder to use.
* @return This request builder.
*/
public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> encoder(
ResourceEncoder<ResourceType> encoder) {
// loadProvider will be null if model is null, in which case we're not going to load anything so it's ok to
// ignore the encoder.
if (loadProvider != null) {
loadProvider.setEncoder(encoder);
}
return this;
}
/**
* Sets the priority for this load.
*
* @param priority A priority.
* @return This request builder.
*/
public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> priority(
Priority priority) {
this.priority = priority;
return this;
}
/**
* Transform resources with the given {@link Transformation}s. Replaces any existing transformation or
* transformations.
*
* @param transformations the transformations to apply in order.
* @return This request builder.
*/
public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> transform(
Transformation<ResourceType>... transformations) {
isTransformationSet = true;
if (transformations.length == 1) {
transformation = transformations[0];
} else {
transformation = new MultiTransformation<ResourceType>(transformations);
}
return this;
}
/**
* Removes the current {@link com.bumptech.glide.load.Transformation}.
*
* @return This request builder.
*/
@SuppressWarnings("unchecked")
public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> dontTransform() {
Transformation<ResourceType> transformation = UnitTransformation.get();
return transform(transformation);
}
/**
* Sets the {@link com.bumptech.glide.load.resource.transcode.ResourceTranscoder} to use for this load.
*
* @see com.bumptech.glide.load.resource.transcode.UnitTranscoder
* @see com.bumptech.glide.load.resource.transcode.GlideBitmapDrawableTranscoder
* @see com.bumptech.glide.load.resource.transcode.GifBitmapWrapperDrawableTranscoder
*
* @param transcoder The transcoder to use.
* @return This request builder.
*/
public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> transcoder(
ResourceTranscoder<ResourceType, TranscodeType> transcoder) {
if (loadProvider != null) {
loadProvider.setTranscoder(transcoder);
}
return this;
}
/**
* Removes any existing animation set on the builder. Will be overridden by subsequent calls that set an animation.
* @return This request builder.
*/
public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> dontAnimate() {
GlideAnimationFactory<TranscodeType> animation = NoAnimation.getFactory();
return animate(animation);
}
/**
* Sets an animation to run on the wrapped target when an resource load finishes. Will only be run if the resource
* was loaded asynchronously (ie was not in the memory cache)
*
* @param animationId The resource id of the animation to run
* @return This request builder.
*/
public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> animate(int animationId) {
return animate(new ViewAnimationFactory<TranscodeType>(context, animationId));
}
/**
* Sets an animation to run on the wrapped target when a resource load finishes. Will only be run if the resource
* was loaded asynchronously (ie was not in the memory cache)
*
* @see #animate(int)
* @see #animate(com.bumptech.glide.request.animation.ViewPropertyAnimation.Animator)
*
* @deprecated If this builder is used for multiple loads, using this method will result in multiple view's being
* asked to start an animation using a single {@link android.view.animation.Animation} object which results in
* views animating repeatedly. Use {@link #animate(int)} or
* {@link #animate(com.bumptech.glide.request.animation.ViewPropertyAnimation.Animator)}. Scheduled to be removed in
* Glide 4.0.
* @param animation The animation to run
* @return This request builder.
*/
@Deprecated
public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> animate(Animation animation) {
return animate(new ViewAnimationFactory<TranscodeType>(animation));
}
/**
* Sets an animator to run a {@link android.view.ViewPropertyAnimator} on a view that the target may be wrapping
* when a resource load finishes. Will only be run if the load was loaded asynchronously (ie was not in the
* memory cache).
*
* @param animator The {@link com.bumptech.glide.request.animation.ViewPropertyAnimation.Animator} to run.
* @return This request builder.
*/
public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> animate(
ViewPropertyAnimation.Animator animator) {
return animate(new ViewPropertyAnimationFactory<TranscodeType>(animator));
}
GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> animate(
GlideAnimationFactory<TranscodeType> animationFactory) {
if (animationFactory == null) {
throw new NullPointerException("Animation factory must not be null!");
}
this.animationFactory = animationFactory;
return this;
}
/**
* Sets an Android resource id for a {@link android.graphics.drawable.Drawable} resourceto display while a resource
* is loading.
*
* @param resourceId The id of the resource to use as a placeholder
* @return This request builder.
*/
public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> placeholder(
int resourceId) {
this.placeholderId = resourceId;
return this;
}
/**
* Sets an {@link android.graphics.drawable.Drawable} to display while a resource is loading.
*
* @param drawable The drawable to display as a placeholder.
* @return This request builder.
*/
public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> placeholder(
Drawable drawable) {
this.placeholderDrawable = drawable;
return this;
}
/**
* Sets a resource to display if a load fails.
*
* @param resourceId The id of the resource to use as a placeholder.
* @return This request builder.
*/
public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> error(
int resourceId) {
this.errorId = resourceId;
return this;
}
/**
* Sets a {@link Drawable} to display if a load fails.
*
* @param drawable The drawable to display.
* @return This request builder.
*/
public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> error(
Drawable drawable) {
this.errorPlaceholder = drawable;
return this;
}
/**
* Sets a RequestBuilder listener to monitor the resource load. It's best to create a single instance of an
* exception handler per type of request (usually activity/fragment) rather than pass one in per request to
* avoid some redundant object allocation.
*
* @param requestListener The request listener to use.
* @return This request builder.
*/
public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> listener(
RequestListener<? super ModelType, TranscodeType> requestListener) {
this.requestListener = requestListener;
return this;
}
/**
* Allows the loaded resource to skip the memory cache.
*
* <p>
* Note - this is not a guarantee. If a request is already pending for this resource and that request is not
* also skipping the memory cache, the resource will be cached in memory.
* </p>
*
* @param skip True to allow the resource to skip the memory cache.
* @return This request builder.
*/
public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> skipMemoryCache(boolean skip) {
this.isCacheable = !skip;
return this;
}
/**
* Overrides the {@link Target}'s width and height with the given values. This is useful almost exclusively for
* thumbnails, and should only be used when you both need a very specific sized image and when it is impossible or
* impractical to return that size from {@link Target#getSize(com.bumptech.glide.request.target.SizeReadyCallback)}.
*
* @param width The width in pixels to use to load the resource.
* @param height The height in pixels to use to load the resource.
* @return This request builder.
*/
public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> override(int width, int height) {
if (width <= 0) {
throw new IllegalArgumentException("Width must be > 0");
}
if (height <= 0) {
throw new IllegalArgumentException("Height must be > 0");
}
this.overrideWidth = width;
this.overrideHeight = height;
return this;
}
/**
* Sets some additional data to be mixed in to the memory and disk cache keys allowing the caller more control over
* when cached data is invalidated.
*
* <p>
* Note - The signature does not replace the cache key, it is purely additive.
* </p>
*
* @see com.bumptech.glide.signature.StringSignature
*
* @param signature A unique non-null {@link com.bumptech.glide.load.Key} representing the current state of the
* model that will be mixed in to the cache key.
* @return This request builder.
*/
public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> signature(Key signature) {
if (signature == null) {
throw new NullPointerException("Signature must not be null");
}
this.signature = signature;
return this;
}
/**
* Sets the specific model to load data for.
*
* <p>
* This method must be called at least once before {@link #into(com.bumptech.glide.request.target.Target)} is
* called.
* </p>
*
* @param model The model to load data for, or null.
* @return This request builder.
*/
public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> load(ModelType model) {
this.model = model;
isModelSet = true;
return this;
}
/**
* Returns a copy of this request builder with all of the options set so far on this builder.
*
* <p>
* This method returns a "deep" copy in that all non-immutable arguments are copied such that changes to one
* builder will not affect the other builder. However, in addition to immutable arguments, the current model
* is not copied copied so changes to the model will affect both builders.
* </p>
*/
@SuppressWarnings("unchecked")
@Override
public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> clone() {
try {
GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> clone =
(GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType>) super.clone();
clone.loadProvider = loadProvider != null ? loadProvider.clone() : null;
return clone;
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
/**
* Set the target the resource will be loaded into.
*
* @see Glide#clear(com.bumptech.glide.request.target.Target)
*
* @param target The target to load the resource into.
* @return The given target.
*/
public <Y extends Target<TranscodeType>> Y into(Y target) {
Util.assertMainThread();
if (target == null) {
throw new IllegalArgumentException("You must pass in a non null Target");
}
if (!isModelSet) {
throw new IllegalArgumentException("You must first set a model (try #load())");
}
Request previous = target.getRequest();
if (previous != null) {
previous.clear();
requestTracker.removeRequest(previous);
previous.recycle();
}
Request request = buildRequest(target);
target.setRequest(request);
lifecycle.addListener(target);
requestTracker.runRequest(request);
return target;
}
/**
* Sets the {@link ImageView} the resource will be loaded into, cancels any existing loads into the view, and frees
* any resources Glide may have previously loaded into the view so they may be reused.
*
* @see Glide#clear(android.view.View)
*
* @param view The view to cancel previous loads for and load the new resource into.
* @return The {@link com.bumptech.glide.request.target.Target} used to wrap the given {@link ImageView}.
*/
public Target<TranscodeType> into(ImageView view) {
Util.assertMainThread();
if (view == null) {
throw new IllegalArgumentException("You must pass in a non null View");
}
if (!isTransformationSet && view.getScaleType() != null) {
switch (view.getScaleType()) {
case CENTER_CROP:
applyCenterCrop();
break;
case FIT_CENTER:
case FIT_START:
case FIT_END:
applyFitCenter();
break;
//$CASES-OMITTED$
default:
// silently ignore
break;
}
}
return into(glide.buildImageViewTarget(view, transcodeClass));
}
/**
* Returns a future that can be used to do a blocking get on a background thread.
*
* @param width The desired width in pixels (note this will be overriden by {@link #override(int, int)} if
* previously called).
* @param height The desired height in pixels (note this will be overriden by {@link #override(int, int)}}
* if previously called).
*
* @see Glide#clear(com.bumptech.glide.request.FutureTarget)
*
* @return An {@link com.bumptech.glide.request.FutureTarget} that can be used to obtain the
* resource in a blocking manner.
*/
public FutureTarget<TranscodeType> into(int width, int height) {
final RequestFutureTarget<ModelType, TranscodeType> target =
new RequestFutureTarget<ModelType, TranscodeType>(glide.getMainHandler(), width, height);
// TODO: Currently all loads must be started on the main thread...
glide.getMainHandler().post(new Runnable() {
@Override
public void run() {
if (!target.isCancelled()) {
into(target);
}
}
});
return target;
}
/**
* Preloads the resource into the cache using the given width and height.
*
* <p>
* Pre-loading is useful for making sure that resources you are going to to want in the near future are
* available quickly.
* </p>
*
* @see com.bumptech.glide.ListPreloader
*/
public Target<TranscodeType> preload(int width, int height) {
final PreloadTarget<TranscodeType> target = PreloadTarget.obtain(width, height);
return into(target);
}
void applyCenterCrop() {
// To be implemented by subclasses when possible.
}
void applyFitCenter() {
// To be implemented by subclasses when possible.
}
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) {
// Recursive case: contains a potentially recursive thumbnail request builder.
if (thumbnailRequestBuilder.animationFactory.equals(NoAnimation.getFactory())) {
thumbnailRequestBuilder.animationFactory = animationFactory;
}
if (thumbnailRequestBuilder.priority == null) {
thumbnailRequestBuilder.priority = getThumbnailPriority();
}
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) {
// 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 {
// Base case: no thumbnail.
return obtainRequest(target, sizeMultiplier, priority, parentCoordinator);
}
}
private Request obtainRequest(Target<TranscodeType> target, float sizeMultiplier, Priority priority,
RequestCoordinator requestCoordinator) {
return GenericRequest.obtain(
loadProvider,
model,
signature,
context,
priority,
target,
sizeMultiplier,
placeholderDrawable,
placeholderId,
errorPlaceholder,
errorId,
requestListener,
requestCoordinator,
glide.getEngine(),
transformation,
transcodeClass,
isCacheable,
animationFactory,
overrideWidth,
overrideHeight,
diskCacheStrategy);
}
}