diff options
author | Sam Judd <judds@google.com> | 2014-10-05 22:03:20 -0700 |
---|---|---|
committer | Sam Judd <judds@google.com> | 2014-10-09 07:36:45 -0700 |
commit | 7d7d03dceae92dc32a9b84dee665a34c300017a7 (patch) | |
tree | 8dc5923108c4827e80d70bd77d5ea2e55d4e5aaf /library/src/main | |
parent | 56ecaaaeda884a1976942d89a151ad363eaf9b6c (diff) | |
download | glide-7d7d03dceae92dc32a9b84dee665a34c300017a7.tar.gz |
Add signature
Fixes #176.
Diffstat (limited to 'library/src/main')
22 files changed, 544 insertions, 289 deletions
diff --git a/library/src/main/java/com/bumptech/glide/BitmapRequestBuilder.java b/library/src/main/java/com/bumptech/glide/BitmapRequestBuilder.java index ce465ea1..6dc00262 100644 --- a/library/src/main/java/com/bumptech/glide/BitmapRequestBuilder.java +++ b/library/src/main/java/com/bumptech/glide/BitmapRequestBuilder.java @@ -1,14 +1,13 @@ package com.bumptech.glide; -import android.content.Context; import android.graphics.Bitmap; import android.graphics.drawable.Drawable; import android.os.ParcelFileDescriptor; import android.view.animation.Animation; import android.widget.ImageView; - import com.bumptech.glide.load.DecodeFormat; import com.bumptech.glide.load.Encoder; +import com.bumptech.glide.load.Key; import com.bumptech.glide.load.ResourceDecoder; import com.bumptech.glide.load.ResourceEncoder; import com.bumptech.glide.load.Transformation; @@ -22,8 +21,6 @@ import com.bumptech.glide.load.resource.bitmap.ImageVideoBitmapDecoder; import com.bumptech.glide.load.resource.bitmap.StreamBitmapDecoder; import com.bumptech.glide.load.resource.bitmap.VideoBitmapDecoder; 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.LoadProvider; import com.bumptech.glide.request.RequestListener; import com.bumptech.glide.request.animation.ViewPropertyAnimation; @@ -47,18 +44,15 @@ import java.io.InputStream; public class BitmapRequestBuilder<ModelType, TranscodeType> extends GenericRequestBuilder<ModelType, ImageVideoWrapper, Bitmap, TranscodeType> implements BitmapOptions { private final BitmapPool bitmapPool; - private final Glide glide; private Downsampler downsampler = Downsampler.AT_LEAST; private DecodeFormat decodeFormat = DecodeFormat.PREFER_RGB_565; private ResourceDecoder<InputStream, Bitmap> imageDecoder; private ResourceDecoder<ParcelFileDescriptor, Bitmap> videoDecoder; - BitmapRequestBuilder(Context context, ModelType model, - LoadProvider<ModelType, ImageVideoWrapper, Bitmap, TranscodeType> streamLoadProvider, - Class<TranscodeType> transcodeClass, Glide glide, RequestTracker requestTracker, Lifecycle lifecycle) { - super(context, model, streamLoadProvider, transcodeClass, glide, requestTracker, lifecycle); - this.glide = glide; - this.bitmapPool = glide.getBitmapPool(); + BitmapRequestBuilder(LoadProvider<ModelType, ImageVideoWrapper, Bitmap, TranscodeType> loadProvider, + Class<TranscodeType> transcodeClass, GenericRequestBuilder<ModelType, ?, ?, ?> other) { + super(loadProvider, transcodeClass, other); + this.bitmapPool = other.glide.getBitmapPool(); imageDecoder = new StreamBitmapDecoder(bitmapPool); videoDecoder = new FileDescriptorBitmapDecoder(bitmapPool); @@ -450,6 +444,12 @@ public class BitmapRequestBuilder<ModelType, TranscodeType> return this; } + @Override + public BitmapRequestBuilder<ModelType, TranscodeType> signature(Key signature) { + super.signature(signature); + return this; + } + /** * {@inheritDoc} * diff --git a/library/src/main/java/com/bumptech/glide/BitmapTypeRequest.java b/library/src/main/java/com/bumptech/glide/BitmapTypeRequest.java index 8e99ef7e..2812e5d6 100644 --- a/library/src/main/java/com/bumptech/glide/BitmapTypeRequest.java +++ b/library/src/main/java/com/bumptech/glide/BitmapTypeRequest.java @@ -1,16 +1,12 @@ package com.bumptech.glide; -import android.content.Context; import android.graphics.Bitmap; import android.os.ParcelFileDescriptor; - import com.bumptech.glide.load.model.ImageVideoModelLoader; import com.bumptech.glide.load.model.ImageVideoWrapper; import com.bumptech.glide.load.model.ModelLoader; import com.bumptech.glide.load.resource.transcode.BitmapBytesTranscoder; 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.DataLoadProvider; import com.bumptech.glide.provider.FixedLoadProvider; @@ -24,14 +20,11 @@ import java.io.InputStream; * @param <ModelType> The type of model to load the {@link Bitmap} or transcoded class from. */ public class BitmapTypeRequest<ModelType> extends BitmapRequestBuilder<ModelType, Bitmap> { - private final Context context; private final ModelType model; private final ModelLoader<ModelType, InputStream> streamModelLoader; private final ModelLoader<ModelType, ParcelFileDescriptor> fileDescriptorModelLoader; private final Glide glide; - private final RequestTracker requestTracker; private final RequestManager.OptionsApplier optionsApplier; - private final Lifecycle lifecycle; private static <A, R> FixedLoadProvider<A, ImageVideoWrapper, Bitmap, R> buildProvider(Glide glide, ModelLoader<A, InputStream> streamModelLoader, @@ -52,22 +45,16 @@ public class BitmapTypeRequest<ModelType> extends BitmapRequestBuilder<ModelType return new FixedLoadProvider<A, ImageVideoWrapper, Bitmap, R>(modelLoader, transcoder, loadProvider); } - BitmapTypeRequest(Context context, ModelType model, + BitmapTypeRequest(GenericRequestBuilder<ModelType, ?, ?, ?> other, ModelLoader<ModelType, InputStream> streamModelLoader, ModelLoader<ModelType, ParcelFileDescriptor> fileDescriptorModelLoader, - Glide glide, RequestTracker requestTracker, Lifecycle lifecycle, RequestManager.OptionsApplier optionsApplier) { - super(context, model, - buildProvider(glide, streamModelLoader, fileDescriptorModelLoader, Bitmap.class, null), - Bitmap.class, - glide, requestTracker, lifecycle); - this.context = context; - this.model = model; + super(buildProvider(other.glide, streamModelLoader, fileDescriptorModelLoader, Bitmap.class, null), + Bitmap.class, other); this.streamModelLoader = streamModelLoader; this.fileDescriptorModelLoader = fileDescriptorModelLoader; - this.glide = glide; - this.requestTracker = requestTracker; - this.lifecycle = lifecycle; + this.model = other.model; + this.glide = other.glide; this.optionsApplier = optionsApplier; } @@ -81,9 +68,9 @@ public class BitmapTypeRequest<ModelType> extends BitmapRequestBuilder<ModelType */ public <R> BitmapRequestBuilder<ModelType, R> transcode(ResourceTranscoder<Bitmap, R> transcoder, Class<R> transcodeClass) { - return optionsApplier.apply(model, new BitmapRequestBuilder<ModelType, R>(context, model, + return optionsApplier.apply(model, new BitmapRequestBuilder<ModelType, R>( buildProvider(glide, streamModelLoader, fileDescriptorModelLoader, transcodeClass, transcoder), - transcodeClass, glide, requestTracker, lifecycle)); + transcodeClass, this)); } /** diff --git a/library/src/main/java/com/bumptech/glide/DrawableRequestBuilder.java b/library/src/main/java/com/bumptech/glide/DrawableRequestBuilder.java index 7dde002d..ce01593a 100644 --- a/library/src/main/java/com/bumptech/glide/DrawableRequestBuilder.java +++ b/library/src/main/java/com/bumptech/glide/DrawableRequestBuilder.java @@ -5,8 +5,8 @@ import android.graphics.Bitmap; 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.ResourceDecoder; import com.bumptech.glide.load.ResourceEncoder; import com.bumptech.glide.load.Transformation; @@ -40,16 +40,11 @@ import java.io.File; public class DrawableRequestBuilder<ModelType> extends GenericRequestBuilder<ModelType, ImageVideoWrapper, GifBitmapWrapper, GlideDrawable> implements BitmapOptions, DrawableOptions { - private final Glide glide; - private final Context context; DrawableRequestBuilder(Context context, ModelType model, LoadProvider<ModelType, ImageVideoWrapper, GifBitmapWrapper, GlideDrawable> loadProvider, Glide glide, RequestTracker requestTracker, Lifecycle lifecycle) { super(context, model, loadProvider, GlideDrawable.class, glide, requestTracker, lifecycle); - this.context = context; - this.glide = glide; - // Default to animating. crossFade(); } @@ -402,6 +397,12 @@ public class DrawableRequestBuilder<ModelType> return this; } + @Override + public DrawableRequestBuilder<ModelType> signature(Key signature) { + super.signature(signature); + return this; + } + /** * {@inheritDoc} * diff --git a/library/src/main/java/com/bumptech/glide/DrawableTypeRequest.java b/library/src/main/java/com/bumptech/glide/DrawableTypeRequest.java index 84520056..21c1139f 100644 --- a/library/src/main/java/com/bumptech/glide/DrawableTypeRequest.java +++ b/library/src/main/java/com/bumptech/glide/DrawableTypeRequest.java @@ -2,7 +2,6 @@ package com.bumptech.glide; import android.content.Context; import android.os.ParcelFileDescriptor; - import com.bumptech.glide.load.model.ImageVideoModelLoader; import com.bumptech.glide.load.model.ImageVideoWrapper; import com.bumptech.glide.load.model.ModelLoader; @@ -30,12 +29,7 @@ import java.io.InputStream; public class DrawableTypeRequest<ModelType> extends DrawableRequestBuilder<ModelType> implements DownloadOptions { private final ModelLoader<ModelType, InputStream> streamModelLoader; private final ModelLoader<ModelType, ParcelFileDescriptor> fileDescriptorModelLoader; - private final Context context; - private final Glide glide; - private final RequestTracker requestTracker; private final RequestManager.OptionsApplier optionsApplier; - private final Lifecycle lifecycle; - private final ModelType model; private static <A, Z, R> FixedLoadProvider<A, ImageVideoWrapper, Z, R> buildProvider(Glide glide, ModelLoader<A, InputStream> streamModelLoader, @@ -63,14 +57,9 @@ public class DrawableTypeRequest<ModelType> extends DrawableRequestBuilder<Model buildProvider(glide, streamModelLoader, fileDescriptorModelLoader, GifBitmapWrapper.class, GlideDrawable.class, null), glide, requestTracker, lifecycle); - this.model = model; this.streamModelLoader = streamModelLoader; this.fileDescriptorModelLoader = fileDescriptorModelLoader; - this.context = context; - this.glide = glide; - this.requestTracker = requestTracker; this.optionsApplier = optionsApplier; - this.lifecycle = lifecycle; } /** @@ -79,8 +68,8 @@ public class DrawableTypeRequest<ModelType> extends DrawableRequestBuilder<Model * @return A new request builder for loading a {@link android.graphics.Bitmap} */ public BitmapTypeRequest<ModelType> asBitmap() { - return optionsApplier.apply(model, new BitmapTypeRequest<ModelType>(context, model, streamModelLoader, - fileDescriptorModelLoader, glide, requestTracker, lifecycle, optionsApplier)); + return optionsApplier.apply(model, new BitmapTypeRequest<ModelType>(this, streamModelLoader, + fileDescriptorModelLoader, optionsApplier)); } /** @@ -96,8 +85,7 @@ public class DrawableTypeRequest<ModelType> extends DrawableRequestBuilder<Model * @return A new request builder for loading a {@link com.bumptech.glide.load.resource.gif.GifDrawable}. */ public GifTypeRequest<ModelType> asGif() { - return optionsApplier.apply(model, new GifTypeRequest<ModelType>(context, model, streamModelLoader, glide, - requestTracker, lifecycle, optionsApplier)); + return optionsApplier.apply(model, new GifTypeRequest<ModelType>(this, streamModelLoader, optionsApplier)); } /** @@ -115,7 +103,7 @@ public class DrawableTypeRequest<ModelType> extends DrawableRequestBuilder<Model } private GenericTranscodeRequest<ModelType, InputStream, File> getDownloadOnlyRequest() { - return optionsApplier.apply(model, new GenericTranscodeRequest<ModelType, InputStream, File>(context, glide, - model, streamModelLoader, InputStream.class, File.class, requestTracker, lifecycle, optionsApplier)); + return optionsApplier.apply(model, new GenericTranscodeRequest<ModelType, InputStream, File>(File.class, this, + streamModelLoader, InputStream.class, File.class, optionsApplier)); } } diff --git a/library/src/main/java/com/bumptech/glide/GenericRequestBuilder.java b/library/src/main/java/com/bumptech/glide/GenericRequestBuilder.java index b56c327b..1d3fc690 100644 --- a/library/src/main/java/com/bumptech/glide/GenericRequestBuilder.java +++ b/library/src/main/java/com/bumptech/glide/GenericRequestBuilder.java @@ -4,8 +4,9 @@ import android.content.Context; import android.graphics.drawable.Drawable; import android.view.animation.Animation; import android.widget.ImageView; - +import com.bumptech.glide.signature.EmptySignature; 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; @@ -49,13 +50,15 @@ import java.io.File; * @param <TranscodeType> The type of resource the decoded resource will be transcoded to. */ public class GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> { - private final Context context; - private final ModelType model; + protected final Context context; + protected final Glide glide; + protected final ModelType model; + protected final Class<TranscodeType> transcodeClass; + protected final RequestTracker requestTracker; + protected final Lifecycle lifecycle; private final ChildLoadProvider<ModelType, DataType, ResourceType, TranscodeType> loadProvider; - private final Class<TranscodeType> transcodeClass; - private final Glide glide; - private final RequestTracker requestTracker; - private final Lifecycle lifecycle; + + private Key signature = EmptySignature.obtain(); private int placeholderId; private int errorId; @@ -74,9 +77,18 @@ public class GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeT 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.model, loadProvider, transcodeClass, other.glide, other.requestTracker, + other.lifecycle); + this.signature = other.signature; + } + GenericRequestBuilder(Context context, ModelType model, LoadProvider<ModelType, DataType, ResourceType, TranscodeType> loadProvider, Class<TranscodeType> transcodeClass, Glide glide, RequestTracker requestTracker, Lifecycle lifecycle) { + this.context = context; + this.model = model; this.transcodeClass = transcodeClass; this.glide = glide; this.requestTracker = requestTracker; @@ -90,8 +102,6 @@ public class GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeT if (model != null && loadProvider == null) { throw new NullPointerException("LoadProvider must not be null"); } - this.context = context; - this.model = model; } /** @@ -505,6 +515,28 @@ public class GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeT } /** + * 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; + } + + /** * Set the target the resource will be loaded into. * * @see Glide#clear(com.bumptech.glide.request.target.Target) @@ -676,6 +708,7 @@ public class GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeT return GenericRequest.obtain( loadProvider, model, + signature, context, priority, target, diff --git a/library/src/main/java/com/bumptech/glide/GenericTranscodeRequest.java b/library/src/main/java/com/bumptech/glide/GenericTranscodeRequest.java index 9960c06c..4274cb6e 100644 --- a/library/src/main/java/com/bumptech/glide/GenericTranscodeRequest.java +++ b/library/src/main/java/com/bumptech/glide/GenericTranscodeRequest.java @@ -1,7 +1,6 @@ package com.bumptech.glide; import android.content.Context; - import com.bumptech.glide.load.engine.DiskCacheStrategy; import com.bumptech.glide.load.model.ModelLoader; import com.bumptech.glide.load.resource.transcode.ResourceTranscoder; @@ -31,15 +30,10 @@ import java.io.File; */ public class GenericTranscodeRequest<ModelType, DataType, ResourceType> extends GenericRequestBuilder<ModelType, DataType, ResourceType, ResourceType> implements DownloadOptions { - private final Context context; - private final ModelType model; - private final Glide glide; private final ModelLoader<ModelType, DataType> modelLoader; private final Class<DataType> dataClass; private final Class<ResourceType> resourceClass; - private final RequestTracker requestTracker; private final RequestManager.OptionsApplier optionsApplier; - private final Lifecycle lifecycle; private static <A, T, Z, R> LoadProvider<A, T, Z, R> build(Glide glide, ModelLoader<A, T> modelLoader, Class<T> dataClass, Class<Z> resourceClass, ResourceTranscoder<Z, R> transcoder) { @@ -47,21 +41,27 @@ public class GenericTranscodeRequest<ModelType, DataType, ResourceType> return new FixedLoadProvider<A, T, Z, R>(modelLoader, transcoder, dataLoadProvider); } + GenericTranscodeRequest( + Class<ResourceType> transcodeClass, GenericRequestBuilder<ModelType, ?, ?, ?> other, + ModelLoader<ModelType, DataType> modelLoader, Class<DataType> dataClass, Class<ResourceType> resourceClass, + RequestManager.OptionsApplier optionsApplier) { + super(build(other.glide, modelLoader, dataClass, resourceClass, UnitTranscoder.<ResourceType>get()), + transcodeClass, other); + this.modelLoader = modelLoader; + this.dataClass = dataClass; + this.resourceClass = resourceClass; + this.optionsApplier = optionsApplier; + } + GenericTranscodeRequest(Context context, Glide glide, ModelType model, ModelLoader<ModelType, DataType> modelLoader, Class<DataType> dataClass, Class<ResourceType> resourceClass, RequestTracker requestTracker, Lifecycle lifecycle, RequestManager.OptionsApplier optionsApplier) { - super(context, model, - build(glide, modelLoader, dataClass, resourceClass, UnitTranscoder.<ResourceType>get()), + super(context, model, build(glide, modelLoader, dataClass, resourceClass, UnitTranscoder.<ResourceType>get()), resourceClass, glide, requestTracker, lifecycle); - this.context = context; - this.model = model; - this.glide = glide; this.modelLoader = modelLoader; this.dataClass = dataClass; this.resourceClass = resourceClass; - this.requestTracker = requestTracker; this.optionsApplier = optionsApplier; - this.lifecycle = lifecycle; } /** @@ -78,8 +78,8 @@ public class GenericTranscodeRequest<ModelType, DataType, ResourceType> dataClass, resourceClass, transcoder); return optionsApplier.apply(model, - new GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType>(context, model, - loadProvider, transcodeClass, glide, requestTracker, lifecycle)); + new GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType>(loadProvider, + transcodeClass, this)); } /** @@ -101,13 +101,10 @@ public class GenericTranscodeRequest<ModelType, DataType, ResourceType> DataLoadProvider<DataType, File> dataLoadProvider = glide.buildDataProvider(dataClass, File.class); FixedLoadProvider<ModelType, DataType, File, File> fixedLoadProvider = new FixedLoadProvider<ModelType, DataType, File, File>(modelLoader, transcoder, dataLoadProvider); - return optionsApplier.apply(model, new GenericRequestBuilder<ModelType, DataType, File, File>(context, model, - fixedLoadProvider, - File.class, glide, - requestTracker, lifecycle) + return optionsApplier.apply(model, new GenericRequestBuilder<ModelType, DataType, File, File>(fixedLoadProvider, + File.class, this)) .priority(Priority.LOW) .diskCacheStrategy(DiskCacheStrategy.SOURCE) - .skipMemoryCache(true)); - + .skipMemoryCache(true); } } diff --git a/library/src/main/java/com/bumptech/glide/GifRequestBuilder.java b/library/src/main/java/com/bumptech/glide/GifRequestBuilder.java index 1059b7ca..d6918f68 100644 --- a/library/src/main/java/com/bumptech/glide/GifRequestBuilder.java +++ b/library/src/main/java/com/bumptech/glide/GifRequestBuilder.java @@ -1,11 +1,10 @@ package com.bumptech.glide; -import android.content.Context; import android.graphics.Bitmap; import android.graphics.drawable.Drawable; import android.view.animation.Animation; - import com.bumptech.glide.load.Encoder; +import com.bumptech.glide.load.Key; import com.bumptech.glide.load.ResourceDecoder; import com.bumptech.glide.load.ResourceEncoder; import com.bumptech.glide.load.Transformation; @@ -14,8 +13,6 @@ import com.bumptech.glide.load.resource.bitmap.BitmapTransformation; import com.bumptech.glide.load.resource.gif.GifDrawable; import com.bumptech.glide.load.resource.gif.GifDrawableTransformation; 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.LoadProvider; import com.bumptech.glide.request.RequestListener; import com.bumptech.glide.request.animation.DrawableCrossFadeViewAnimation; @@ -37,15 +34,10 @@ import java.io.InputStream; public class GifRequestBuilder<ModelType> extends GenericRequestBuilder<ModelType, InputStream, GifDrawable, GifDrawable> implements BitmapOptions, DrawableOptions { - private final Context context; - private final Glide glide; - GifRequestBuilder(Context context, ModelType model, - LoadProvider<ModelType, InputStream, GifDrawable, GifDrawable> loadProvider, Glide glide, - RequestTracker requestTracker, Lifecycle lifecycle) { - super(context, model, loadProvider, GifDrawable.class, glide, requestTracker, lifecycle); - this.context = context; - this.glide = glide; + GifRequestBuilder(LoadProvider<ModelType, InputStream, GifDrawable, GifDrawable> loadProvider, + Class<GifDrawable> transcodeClass, GenericRequestBuilder<ModelType, ?, ?, ?> other) { + super(loadProvider, transcodeClass, other); } /** @@ -397,6 +389,12 @@ public class GifRequestBuilder<ModelType> } @Override + public GifRequestBuilder<ModelType> signature(Key signature) { + super.signature(signature); + return this; + } + + @Override void applyFitCenter() { fitCenter(); } diff --git a/library/src/main/java/com/bumptech/glide/GifTypeRequest.java b/library/src/main/java/com/bumptech/glide/GifTypeRequest.java index 857e516f..bded0f99 100644 --- a/library/src/main/java/com/bumptech/glide/GifTypeRequest.java +++ b/library/src/main/java/com/bumptech/glide/GifTypeRequest.java @@ -1,13 +1,9 @@ package com.bumptech.glide; -import android.content.Context; - import com.bumptech.glide.load.model.ModelLoader; import com.bumptech.glide.load.resource.gif.GifDrawable; import com.bumptech.glide.load.resource.transcode.GifDrawableBytesTranscoder; 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.DataLoadProvider; import com.bumptech.glide.provider.FixedLoadProvider; @@ -22,13 +18,8 @@ import java.io.InputStream; * transcoded class from. */ public class GifTypeRequest<ModelType> extends GifRequestBuilder<ModelType> { - private final Context context; - private final ModelType model; private final ModelLoader<ModelType, InputStream> streamModelLoader; - private final Glide glide; - private final RequestTracker requestTracker; private final RequestManager.OptionsApplier optionsApplier; - private final Lifecycle lifecycle; private static <A, R> FixedLoadProvider<A, InputStream, GifDrawable, R> buildProvider(Glide glide, ModelLoader<A, InputStream> streamModelLoader, Class<R> transcodeClass, @@ -45,17 +36,11 @@ public class GifTypeRequest<ModelType> extends GifRequestBuilder<ModelType> { return new FixedLoadProvider<A, InputStream, GifDrawable, R>(streamModelLoader, transcoder, dataLoadProvider); } - GifTypeRequest(Context context, ModelType model, ModelLoader<ModelType, InputStream> streamModelLoader, Glide glide, - RequestTracker requestTracker, Lifecycle lifecycle, RequestManager.OptionsApplier optionsApplier) { - super(context, model, buildProvider(glide, streamModelLoader, GifDrawable.class, null), glide, - requestTracker, lifecycle); - this.context = context; - this.model = model; + GifTypeRequest(GenericRequestBuilder<ModelType, ?, ?, ?> other, + ModelLoader<ModelType, InputStream> streamModelLoader, RequestManager.OptionsApplier optionsApplier) { + super(buildProvider(other.glide, streamModelLoader, GifDrawable.class, null), GifDrawable.class, other); this.streamModelLoader = streamModelLoader; - this.glide = glide; - this.requestTracker = requestTracker; this.optionsApplier = optionsApplier; - this.lifecycle = lifecycle; // Default to animating. crossFade(); @@ -77,8 +62,8 @@ public class GifTypeRequest<ModelType> extends GifRequestBuilder<ModelType> { ResourceTranscoder<GifDrawable, R> transcoder, Class<R> transcodeClass) { FixedLoadProvider<ModelType, InputStream, GifDrawable, R> provider = buildProvider(glide, streamModelLoader, transcodeClass, transcoder); - return optionsApplier.apply(model, new GenericRequestBuilder<ModelType, InputStream, GifDrawable, R>(context, - model, provider, transcodeClass, glide, requestTracker, lifecycle)); + return optionsApplier.apply(model, + new GenericRequestBuilder<ModelType, InputStream, GifDrawable, R>(provider, transcodeClass, this)); } /** diff --git a/library/src/main/java/com/bumptech/glide/RequestManager.java b/library/src/main/java/com/bumptech/glide/RequestManager.java index 3e2b751b..3b6ba991 100644 --- a/library/src/main/java/com/bumptech/glide/RequestManager.java +++ b/library/src/main/java/com/bumptech/glide/RequestManager.java @@ -5,7 +5,6 @@ import android.net.Uri; import android.os.Handler; import android.os.Looper; import android.os.ParcelFileDescriptor; - import com.bumptech.glide.load.model.ModelLoader; import com.bumptech.glide.load.model.file_descriptor.FileDescriptorModelLoader; import com.bumptech.glide.load.model.stream.MediaStoreStreamLoader; @@ -36,7 +35,7 @@ import java.util.UUID; */ public class RequestManager implements LifecycleListener { private final Context context; - private Lifecycle lifecycle; + private final Lifecycle lifecycle; private final RequestTracker requestTracker; private final Glide glide; private final OptionsApplier optionsApplier; @@ -167,98 +166,111 @@ public class RequestManager implements LifecycleListener { } /** - * Use the given generic model loader to load the given generic data class. + * Returns a request builder that uses the given {@link com.bumptech.glide.load.model.ModelLoader} to fetch a + * generic data type. + * * <p> * Warning - This is an experimental api that may change without a change in major version. * </p> + * * @param modelLoader The {@link ModelLoader} class to use to load the model. * @param dataClass The type of data the {@link ModelLoader} will load. * @param <A> The type of the model to be loaded. * @param <T> The type of the data to be loaded from the mode. - * @return A {@link GenericModelRequest} to set options for the load and ultimately the target to load the model - * into. */ public <A, T> GenericModelRequest<A, T> using(ModelLoader<A, T> modelLoader, Class<T> dataClass) { return new GenericModelRequest<A, T>(modelLoader, dataClass); } /** - * Set the {@link ModelLoader} to use for for a new load where the model loader translates from a model to an - * {@link InputStream} resource for loading images. + * Returns a request builder that uses the given {@link com.bumptech.glide.load.model.stream.StreamModelLoader} to + * fetch an {@link InputStream} for loading images. * * @param modelLoader The model loader to use. * @param <T> The type of the model. - * @return A new {@link ImageModelRequest}. */ public <T> ImageModelRequest<T> using(final StreamModelLoader<T> modelLoader) { return new ImageModelRequest<T>(modelLoader); } /** - * A convenience method to use a {@link StreamByteArrayLoader} to decode an image from a byte array. + * Returns a request builder that uses the given + * {@link com.bumptech.glide.load.model.stream.StreamByteArrayLoader} to fetch an {@link java.io.InputStream} for + * loading Bitmaps. * * @param modelLoader The byte array loader. - * @return A new {@link ImageModelRequest}. */ public ImageModelRequest<byte[]> using(StreamByteArrayLoader modelLoader) { return new ImageModelRequest<byte[]>(modelLoader); } /** - * Set the {@link ModelLoader} to use for a new load where the model loader translates from a model to an - * {@link ParcelFileDescriptor} resource for loading video thumbnails. + * Returns a new request builder that uses the given {@link ModelLoader} to fetch a + * {@link ParcelFileDescriptor} for loading video thumbnails. * * @param modelLoader The model loader to use. * @param <T> The type of the model. - * @return A new {@link VideoModelRequest}. */ public <T> VideoModelRequest<T> using(final FileDescriptorModelLoader<T> modelLoader) { return new VideoModelRequest<T>(modelLoader); } /** - * Use the {@link com.bumptech.glide.load.model.ModelLoaderFactory} currently registered for {@link String} to load - * the image represented by the given {@link String}. Defaults to - * {@link com.bumptech.glide.load.model.stream.StreamStringLoader.Factory} and - * {@link com.bumptech.glide.load.model.stream.StreamStringLoader} to load the given model. + * Returns a request builder to load the data represented by the given {@link String} using an empty + * signature. * - * @see #using(StreamModelLoader) + * <p> + * Note - this method caches data using only the given String as the cache key. If the data is a Uri outside of + * your control, or you otherwise expect the data represented by the given String to change without the String + * identifier changing, Consider using + * {@link com.bumptech.glide.GenericRequestBuilder#signature(com.bumptech.glide.load.Key)} to mixin a signature + * you create that identifies the data currently at the given String that will invalidate the cache if that data + * changes. Alternatively, using {@link com.bumptech.glide.load.engine.DiskCacheStrategy#NONE} and/or + * {@link com.bumptech.glide.DrawableRequestBuilder#skipMemoryCache(boolean)} may be appropriate. + * </p> * - * @param string The string representing the image. Must be either a path, or a uri handled by - * {@link com.bumptech.glide.load.model.stream.StreamUriLoader} - * @return A {@link DrawableTypeRequest} to set options for the load and ultimately the target to load the model - * into. + * @see com.bumptech.glide.GenericRequestBuilder#signature(com.bumptech.glide.load.Key) + * + * @param string A file path, or a uri or url handled by {@link com.bumptech.glide.load.model.UriLoader}. */ public DrawableTypeRequest<String> load(String string) { return loadGeneric(string); } /** - * Use the {@link com.bumptech.glide.load.model.ModelLoaderFactory} currently registered for {@link Uri} to load the - * image at the given uri. Defaults to {@link com.bumptech.glide.load.model.stream.StreamUriLoader.Factory} and - * {@link com.bumptech.glide.load.model.stream.StreamUriLoader}. + * Returns a request builder to load the data represented by the given {@link Uri} using an empty signature. * - * @see #using(StreamModelLoader) + * <p> + * Note - this method caches data at Uris using only the Uri itself as the cache key. The data represented by + * Uris from some content providers may change without the Uri changing, which means using this method + * can lead to displaying stale data. Consider using + * {@link com.bumptech.glide.GenericRequestBuilder#signature(com.bumptech.glide.load.Key)} to mixin a signature + * you create based on the data at the given Uri that will invalidate the cache if that data changes. + * Alternatively, using {@link com.bumptech.glide.load.engine.DiskCacheStrategy#NONE} and/or + * {@link com.bumptech.glide.DrawableRequestBuilder#skipMemoryCache(boolean)} may be appropriate. + * </p> * - * @param uri The uri representing the image. Must be a uri handled by - * {@link com.bumptech.glide.load.model.stream.StreamUriLoader} - * @return A {@link DrawableTypeRequest} to set options for the load and ultimately the target to load the model - * into. + * @see #using(com.bumptech.glide.load.model.stream.StreamModelLoader) + * @see #loadFromMediaStore(android.net.Uri) + * @see #loadFromMediaStore(android.net.Uri, String, long, int) + * @see com.bumptech.glide.GenericRequestBuilder#signature(com.bumptech.glide.load.Key) + * + * @param uri The Uri representing the image. Must be of a type handled by + * {@link com.bumptech.glide.load.model.UriLoader}. */ public DrawableTypeRequest<Uri> load(Uri uri) { return loadGeneric(uri); } /** - * Use {@link android.provider.MediaStore.Images.Thumbnails} and - * {@link android.provider.MediaStore.Video.Thumbnails} to retrieve pre-generated thumbnails for the given uri. + * Returns a request builder that uses {@link android.provider.MediaStore.Images.Thumbnails} and + * {@link android.provider.MediaStore.Video.Thumbnails} to retrieve pre-generated thumbnails for the given uri if + * available and uses the given additional data to build a unique signature for cache invalidation. * - * <p> - * Falls back to the registered {@link com.bumptech.glide.load.model.ModelLoaderFactory} registered for - * {@link Uri}s if the given uri is not a media store uri or if no pre-generated thumbnail exists for the given - * uri. In addition, mixes the given mimeType, dateModified, and orientation into the cache key to detect and - * invalidate thumbnails if content is changed locally. - * </p> + * @see #loadFromMediaStore(android.net.Uri) + * @see #load(android.net.Uri) + * @see com.bumptech.glide.GenericRequestBuilder#signature(com.bumptech.glide.load.Key) + * @see com.bumptech.glide.signature.MediaStoreSignature * * @param uri The uri representing the media. * @param mimeType The mime type of the media store media. Ok to default to empty string "". See @@ -269,88 +281,140 @@ public class RequestManager implements LifecycleListener { * {@link android.provider.MediaStore.Video.VideoColumns#DATE_MODIFIED}. * @param orientation The orientation of the media store media. Ok to default to 0. See * {@link android.provider.MediaStore.Images.ImageColumns#ORIENTATION}. - * @return A new {@link DrawableRequestBuilder} to set options for the load and ultimately the target to load the - * uri into. */ public DrawableTypeRequest<Uri> loadFromMediaStore(Uri uri, String mimeType, long dateModified, int orientation) { + // TODO: create a signature from the given arguments. + return loadFromMediaStore(uri); + } + + /** + * Returns a request builder that uses {@link android.provider.MediaStore.Images.Thumbnails} and + * {@link android.provider.MediaStore.Video.Thumbnails} to retrieve pre-generated thumbnails for the given uri. + * + * <p> + * Falls back to the registered {@link com.bumptech.glide.load.model.ModelLoaderFactory} registered for + * {@link Uri}s if the given uri is not a media store uri or if no pre-generated thumbnail exists for the given + * uri. + * </p> + * + * <p> + * Note - This method by default caches data using the given Uri as the key. Since content in the media store + * can change at any time, you should use + * {@link com.bumptech.glide.GenericRequestBuilder#signature(com.bumptech.glide.load.Key)} to mix in some + * additional data identifying the current state of the Uri, preferably using + * {@link com.bumptech.glide.signature.MediaStoreSignature}. Alternatively consider avoiding the memory and + * disk caches entirely using + * {@link GenericRequestBuilder#diskCacheStrategy(com.bumptech.glide.load.engine.DiskCacheStrategy)} + * and {@link com.bumptech.glide.load.engine.DiskCacheStrategy#NONE} and/or + * {@link com.bumptech.glide.GenericRequestBuilder#skipMemoryCache(boolean)}. + * </p> + * + * @see #loadFromMediaStore(android.net.Uri, String, long, int) + * @see #load(android.net.Uri) + * @see com.bumptech.glide.GenericRequestBuilder#signature(com.bumptech.glide.load.Key) + * @see com.bumptech.glide.signature.MediaStoreSignature + * + * @param uri The uri representing the media. + */ + public DrawableTypeRequest<Uri> loadFromMediaStore(Uri uri) { ModelLoader<Uri, InputStream> genericStreamLoader = Glide.buildStreamModelLoader(uri, context); - ModelLoader<Uri, InputStream> mediaStoreLoader = new MediaStoreStreamLoader(context, genericStreamLoader, - mimeType, dateModified, orientation); + ModelLoader<Uri, InputStream> mediaStoreLoader = new MediaStoreStreamLoader(context, genericStreamLoader); ModelLoader<Uri, ParcelFileDescriptor> fileDescriptorModelLoader = Glide.buildFileDescriptorModelLoader(uri, context); - return optionsApplier.apply(uri, new DrawableTypeRequest<Uri>(uri, mediaStoreLoader, fileDescriptorModelLoader, - context, glide, requestTracker, lifecycle, optionsApplier)); + + return optionsApplier.apply(uri, new DrawableTypeRequest<Uri>(uri, mediaStoreLoader, + fileDescriptorModelLoader, context, glide, requestTracker, lifecycle, optionsApplier)); } /** - * Use the {@link com.bumptech.glide.load.model.ModelLoaderFactory} currently registered for {@link File} to load - * the image represented by the given {@link File}. Defaults to + * Returns a request builder that uses the {@link com.bumptech.glide.load.model.ModelLoaderFactory} currently + * registered for {@link File} to load the image represented by the given {@link File}. Defaults to * {@link com.bumptech.glide.load.model.stream.StreamFileLoader.Factory} and * {@link com.bumptech.glide.load.model.stream.StreamFileLoader} to load the given model. * + * <p> + * Note - this method caches data for Files using only the file path itself as the cache key. The data in the + * File can change so using this method can lead to displaying stale data. If you expect the data in the File to + * change, Consider using + * {@link com.bumptech.glide.GenericRequestBuilder#signature(com.bumptech.glide.load.Key)} to mixin a signature + * you create that identifies the data currently in the File that will invalidate the cache if that data + * changes. Alternatively, using {@link com.bumptech.glide.load.engine.DiskCacheStrategy#NONE} and/or + * {@link com.bumptech.glide.DrawableRequestBuilder#skipMemoryCache(boolean)} may be appropriate. + * </p> + * + * @see #load(java.io.File) * @see #using(StreamModelLoader) * * @param file The File containing the image - * @return A {@link DrawableTypeRequest} to set options for the load and ultimately the target to load the model - * into. */ public DrawableTypeRequest<File> load(File file) { return loadGeneric(file); } /** - * Use the {@link com.bumptech.glide.load.model.ModelLoaderFactory} currently registered for {@link Integer} to load - * the image represented by the given {@link Integer} resource id. Defaults to - * {@link com.bumptech.glide.load.model.stream.StreamResourceLoader.Factory} and + * Returns a request builder that uses the {@link com.bumptech.glide.load.model.ModelLoaderFactory} currently + * registered for {@link Integer} to load the image represented by the given {@link Integer} resource id. Defaults + * to {@link com.bumptech.glide.load.model.stream.StreamResourceLoader.Factory} and * {@link com.bumptech.glide.load.model.stream.StreamResourceLoader} to load the given model. * + * <p> + * By default this method adds a version code based signature to the cache key used to cache this resource in + * Glide. This signature is sufficient to guarantee that end users will see the most up to date versions of + * your Drawables, but during development if you do not increment your version code before each install and + * you replace a Drawable with different data without changing the Drawable name, you may see inconsistent + * cached data. To get around this, consider using {@link com.bumptech.glide.load.engine.DiskCacheStrategy#NONE} + * via {@link GenericRequestBuilder#diskCacheStrategy(com.bumptech.glide.load.engine.DiskCacheStrategy)} + * during development, and re-enabling the default + * {@link com.bumptech.glide.load.engine.DiskCacheStrategy#RESULT} for release builds. + * </p> + * + * @see #load(Integer) * @see #using(StreamModelLoader) * * @param resourceId the id of the resource containing the image - * @return A {@link DrawableTypeRequest} to set options for the load and ultimately the target to load the model - * into. */ public DrawableTypeRequest<Integer> load(Integer resourceId) { return loadGeneric(resourceId); } /** - * Use the {@link com.bumptech.glide.load.model.ModelLoaderFactory} currently registered for {@link URL} to load the - * image represented by the given {@link URL}. Defaults to + * Returns a request builder that uses the {@link com.bumptech.glide.load.model.ModelLoaderFactory} currently + * registered for {@link URL} to load the image represented by the given {@link URL}. Defaults to * {@link com.bumptech.glide.load.model.stream.HttpUrlGlideUrlLoader} and * {@link com.bumptech.glide.load.data.HttpUrlFetcher} to load the given model. * * @see #using(StreamModelLoader) * * @param url The URL representing the image. - * @return A {@link DrawableTypeRequest} to set options for the load and ultimately the target to load the model - * into. */ public DrawableTypeRequest<URL> load(URL url) { return loadGeneric(url); } /** - * Use a new {@link StreamByteArrayLoader} to load an image from the given model. + * Returns a request builder that uses a {@link StreamByteArrayLoader} to load an image from the given byte array. * * @see #load(byte[]) * * @param model The data to load. * @param id A unique id that identifies the image represented by the model suitable for use as a cache key - * (url, filepath etc). If there is no suitable id, use {@link #load(byte[])} instaed. + * (url, filepath etc). If there is no suitable id, use {@link #load(byte[])} instead. * @return A {@link DrawableTypeRequest} to set options for the load and ultimately the target to load the image * into. */ public DrawableTypeRequest<byte[]> load(byte[] model, final String id) { final StreamByteArrayLoader loader = new StreamByteArrayLoader(id); + // TODO: just use signature instead of id here? return optionsApplier.apply(model, new DrawableTypeRequest<byte[]>(model, loader, null, context, glide, requestTracker, lifecycle, optionsApplier)); } /** - * Use a new {@link StreamByteArrayLoader} to load an image from the given model. Suitable when there is no - * simple id that represents the given data. + * Returns a request builder that uses {@link StreamByteArrayLoader} to load an image from the given byte array. + * Suitable when there is no simple id that represents the given data. + * + * @see #load(byte[], String) * * @param model the data to load. * @return A {@link DrawableTypeRequest} to set options for the load and ultimately the target to load the image @@ -361,14 +425,14 @@ public class RequestManager implements LifecycleListener { } /** - * Use the {@link com.bumptech.glide.load.model.ModelLoaderFactory}s currently registered for the given model type - * for {@link InputStream}s and {@link ParcelFileDescriptor}s to load a thumbnail from either the image or the video - * represented by the given model. + * Returns a request builder that uses the {@link com.bumptech.glide.load.model.ModelLoaderFactory}s currently + * registered for the given model Class for {@link InputStream}s and {@link ParcelFileDescriptor}s to load a + * thumbnail from either the image or the video represented by the given model. + * + * @see #load(Object) * * @param model The model the load. * @param <T> The type of the model to load. - * @return A {@link DrawableTypeRequest} to set options for the load and ultimately the target to load the image - * into. */ public <T> DrawableTypeRequest<T> load(T model) { return loadGeneric(model); @@ -401,8 +465,8 @@ public class RequestManager implements LifecycleListener { } public DrawableTypeRequest<T> load(T model) { - return optionsApplier.apply(model, new DrawableTypeRequest<T>(model, null, loader, context, glide, - requestTracker, lifecycle, optionsApplier)); + return optionsApplier.apply(model, new DrawableTypeRequest<T>(model, null, loader, context, + glide, requestTracker, lifecycle, optionsApplier)); } } @@ -420,8 +484,8 @@ public class RequestManager implements LifecycleListener { } public DrawableTypeRequest<T> load(T model) { - return optionsApplier.apply(model, new DrawableTypeRequest<T>(model, loader, null, context, glide, - requestTracker, lifecycle, optionsApplier)); + return optionsApplier.apply(model, new DrawableTypeRequest<T>(model, loader, null, context, + glide, requestTracker, lifecycle, optionsApplier)); } } @@ -486,7 +550,6 @@ public class RequestManager implements LifecycleListener { } return builder; } - } private static class RequestManagerConnectivityListener implements ConnectivityMonitor.ConnectivityListener { diff --git a/library/src/main/java/com/bumptech/glide/load/Key.java b/library/src/main/java/com/bumptech/glide/load/Key.java index 58462256..4f614ed1 100644 --- a/library/src/main/java/com/bumptech/glide/load/Key.java +++ b/library/src/main/java/com/bumptech/glide/load/Key.java @@ -4,26 +4,28 @@ import java.io.UnsupportedEncodingException; import java.security.MessageDigest; /** - * A very generic interface that must implement {@link Object#equals(Object)} and {@link Object#hashCode()} to include a - * set of uniquely identifying information for the object(s) represented by this key. Keys are used as cache keys so - * they must be unique within a given dataset. - * + * An interface that uniquely identifies some set of data. Implementations must implement {@link Object#equals(Object)} + * and {@link Object#hashCode()}. Implementations are generally expected to add all uniquely identifying information + * used in in {@link java.lang.Object#equals(Object)}} and {@link Object#hashCode()}} to the given + * {@link java.security.MessageDigest} in {@link #updateDiskCacheKey(java.security.MessageDigest)}}, although this + * requirement is not as strict for partial cache key signatures. */ public interface Key { + String STRING_CHARSET_NAME = "UTF-8"; + /** * Adds all uniquely identifying information to the given digest. + * + * <p> + * Note - Using {@link java.security.MessageDigest#reset()} inside of this method will result in undefined + * behavior. + * </p> */ void updateDiskCacheKey(MessageDigest messageDigest) throws UnsupportedEncodingException; - /** - * {@inheritDoc} - */ @Override boolean equals(Object o); - /** - * {@inheritDoc} - */ @Override int hashCode(); } diff --git a/library/src/main/java/com/bumptech/glide/load/data/MediaStoreThumbFetcher.java b/library/src/main/java/com/bumptech/glide/load/data/MediaStoreThumbFetcher.java index 2b292a95..af47dd2f 100644 --- a/library/src/main/java/com/bumptech/glide/load/data/MediaStoreThumbFetcher.java +++ b/library/src/main/java/com/bumptech/glide/load/data/MediaStoreThumbFetcher.java @@ -30,28 +30,21 @@ public class MediaStoreThumbFetcher implements DataFetcher<InputStream> { private final DataFetcher<InputStream> defaultFetcher; private final int width; private final int height; - private final long dateModified; - private final int orientation; private final ThumbnailStreamOpenerFactory factory; private InputStream inputStream; - private String mimeType; public MediaStoreThumbFetcher(Context context, Uri mediaStoreUri, DataFetcher<InputStream> defaultFetcher, - int width, int height, String mimeType, long dateModified, int orientation) { - this(context, mediaStoreUri, defaultFetcher, width, height, mimeType, dateModified, orientation, - DEFAULT_FACTORY); + int width, int height) { + this(context, mediaStoreUri, defaultFetcher, width, height, DEFAULT_FACTORY); } MediaStoreThumbFetcher(Context context, Uri mediaStoreUri, DataFetcher<InputStream> defaultFetcher, int width, - int height, String mimeType, long dateModified, int orientation, ThumbnailStreamOpenerFactory factory) { + int height, ThumbnailStreamOpenerFactory factory) { this.context = context; this.mediaStoreUri = mediaStoreUri; this.defaultFetcher = defaultFetcher; this.width = width; this.height = height; - this.mimeType = mimeType; - this.dateModified = dateModified; - this.orientation = orientation; this.factory = factory; } @@ -84,7 +77,7 @@ public class MediaStoreThumbFetcher implements DataFetcher<InputStream> { @Override public String getId() { - return mediaStoreUri + mimeType + dateModified + orientation; + return mediaStoreUri.toString(); } @Override diff --git a/library/src/main/java/com/bumptech/glide/load/engine/Engine.java b/library/src/main/java/com/bumptech/glide/load/engine/Engine.java index abda85e9..c2a6a389 100644 --- a/library/src/main/java/com/bumptech/glide/load/engine/Engine.java +++ b/library/src/main/java/com/bumptech/glide/load/engine/Engine.java @@ -118,6 +118,8 @@ public class Engine implements EngineJobListener, MemoryCache.ResourceRemovedLis * held weakly. * </p> * + * @param signature A non-null unique key to be mixed into the cache key that identifies the version of the data to + * be loaded. * @param width The target width of the retrieved resource. * @param height The target height of the retrieved resource. * @param cacheDecoder The decoder to use to decode data already in the disk cache. @@ -137,7 +139,7 @@ public class Engine implements EngineJobListener, MemoryCache.ResourceRemovedLis * @param <Z> The type of the resource that will be decoded. * @param <R> The type of the resource that will be transcoded from the decoded resource. */ - public <T, Z, R> LoadStatus load(int width, int height, ResourceDecoder<File, Z> cacheDecoder, + public <T, Z, R> LoadStatus load(Key signature, int width, int height, ResourceDecoder<File, Z> cacheDecoder, DataFetcher<T> fetcher, Encoder<T> sourceEncoder, ResourceDecoder<T, Z> decoder, Transformation<Z> transformation, ResourceEncoder<Z> encoder, ResourceTranscoder<Z, R> transcoder, Priority priority, boolean isMemoryCacheable, DiskCacheStrategy diskCacheStrategy, ResourceCallback cb) { @@ -145,8 +147,8 @@ public class Engine implements EngineJobListener, MemoryCache.ResourceRemovedLis long startTime = LogTime.getLogTime(); final String id = fetcher.getId(); - EngineKey key = keyFactory.buildKey(id, width, height, cacheDecoder, decoder, transformation, encoder, - transcoder, sourceEncoder); + EngineKey key = keyFactory.buildKey(id, signature, width, height, cacheDecoder, decoder, transformation, + encoder, transcoder, sourceEncoder); EngineResource<?> cached = getFromCache(key); if (cached != null) { diff --git a/library/src/main/java/com/bumptech/glide/load/engine/EngineKey.java b/library/src/main/java/com/bumptech/glide/load/engine/EngineKey.java index 2755b7ae..7cbbe6f2 100644 --- a/library/src/main/java/com/bumptech/glide/load/engine/EngineKey.java +++ b/library/src/main/java/com/bumptech/glide/load/engine/EngineKey.java @@ -5,7 +5,6 @@ import com.bumptech.glide.load.Key; import com.bumptech.glide.load.ResourceDecoder; import com.bumptech.glide.load.ResourceEncoder; import com.bumptech.glide.load.Transformation; -import com.bumptech.glide.load.engine.cache.StringKey; import com.bumptech.glide.load.resource.transcode.ResourceTranscoder; import java.io.UnsupportedEncodingException; @@ -14,8 +13,6 @@ import java.security.MessageDigest; @SuppressWarnings("rawtypes") class EngineKey implements Key { - private static final String FORMAT = "UTF-8"; - private final String id; private final int width; private final int height; @@ -25,14 +22,16 @@ class EngineKey implements Key { private final ResourceEncoder encoder; private final ResourceTranscoder transcoder; private final Encoder sourceEncoder; + private final Key signature; private String stringKey; private int hashCode; - private StringKey originalKey; + private Key originalKey; - public EngineKey(String id, int width, int height, ResourceDecoder cacheDecoder, ResourceDecoder decoder, - Transformation transformation, ResourceEncoder encoder, ResourceTranscoder transcoder, - Encoder sourceEncoder) { + public EngineKey(String id, Key signature, int width, int height, ResourceDecoder cacheDecoder, + ResourceDecoder decoder, Transformation transformation, ResourceEncoder encoder, + ResourceTranscoder transcoder, Encoder sourceEncoder) { this.id = id; + this.signature = signature; this.width = width; this.height = height; this.cacheDecoder = cacheDecoder; @@ -45,7 +44,7 @@ class EngineKey implements Key { public Key getOriginalKey() { if (originalKey == null) { - originalKey = new StringKey(id); + originalKey = new OriginalKey(id, signature); } return originalKey; } @@ -63,6 +62,8 @@ class EngineKey implements Key { if (!id.equals(engineKey.id)) { return false; + } else if (!signature.equals(engineKey.signature)) { + return false; } else if (height != engineKey.height) { return false; } else if (width != engineKey.width) { @@ -99,6 +100,7 @@ class EngineKey implements Key { public int hashCode() { if (hashCode == 0) { hashCode = id.hashCode(); + hashCode = 31 * hashCode + signature.hashCode(); hashCode = 31 * hashCode + width; hashCode = 31 * hashCode + height; hashCode = 31 * hashCode + (cacheDecoder != null ? cacheDecoder .getId().hashCode() : 0); @@ -116,6 +118,7 @@ class EngineKey implements Key { if (stringKey == null) { stringKey = new StringBuilder() .append(id) + .append(signature) .append(width) .append(height) .append(cacheDecoder != null ? cacheDecoder .getId() : "") @@ -135,13 +138,14 @@ class EngineKey implements Key { .putInt(width) .putInt(height) .array(); - messageDigest.update(id.getBytes(FORMAT)); + signature.updateDiskCacheKey(messageDigest); + messageDigest.update(id.getBytes(STRING_CHARSET_NAME)); messageDigest.update(dimensions); - messageDigest.update((cacheDecoder != null ? cacheDecoder .getId() : "").getBytes(FORMAT)); - messageDigest.update((decoder != null ? decoder .getId() : "").getBytes(FORMAT)); - messageDigest.update((transformation != null ? transformation.getId() : "").getBytes(FORMAT)); - messageDigest.update((encoder != null ? encoder .getId() : "").getBytes(FORMAT)); - // transcoder is not playing in disk cache key, since it's after in the workflow - messageDigest.update((sourceEncoder != null ? sourceEncoder .getId() : "").getBytes(FORMAT)); + messageDigest.update((cacheDecoder != null ? cacheDecoder .getId() : "").getBytes(STRING_CHARSET_NAME)); + messageDigest.update((decoder != null ? decoder .getId() : "").getBytes(STRING_CHARSET_NAME)); + messageDigest.update((transformation != null ? transformation.getId() : "").getBytes(STRING_CHARSET_NAME)); + messageDigest.update((encoder != null ? encoder .getId() : "").getBytes(STRING_CHARSET_NAME)); + // The Transcoder is not included in the disk cache key because its result is not cached. + messageDigest.update((sourceEncoder != null ? sourceEncoder .getId() : "").getBytes(STRING_CHARSET_NAME)); } } diff --git a/library/src/main/java/com/bumptech/glide/load/engine/EngineKeyFactory.java b/library/src/main/java/com/bumptech/glide/load/engine/EngineKeyFactory.java index a08c9e4d..029266a7 100644 --- a/library/src/main/java/com/bumptech/glide/load/engine/EngineKeyFactory.java +++ b/library/src/main/java/com/bumptech/glide/load/engine/EngineKeyFactory.java @@ -1,6 +1,7 @@ package com.bumptech.glide.load.engine; import com.bumptech.glide.load.Encoder; +import com.bumptech.glide.load.Key; import com.bumptech.glide.load.ResourceDecoder; import com.bumptech.glide.load.ResourceEncoder; import com.bumptech.glide.load.Transformation; @@ -9,11 +10,11 @@ import com.bumptech.glide.load.resource.transcode.ResourceTranscoder; class EngineKeyFactory { @SuppressWarnings("rawtypes") - public EngineKey buildKey(String id, int width, int height, ResourceDecoder cacheDecoder, + public EngineKey buildKey(String id, Key signature, int width, int height, ResourceDecoder cacheDecoder, ResourceDecoder sourceDecoder, Transformation transformation, ResourceEncoder encoder, ResourceTranscoder transcoder, Encoder sourceEncoder) { - return new EngineKey(id, width, height, cacheDecoder, sourceDecoder, transformation, encoder, transcoder, - sourceEncoder); + return new EngineKey(id, signature, width, height, cacheDecoder, sourceDecoder, transformation, encoder, + transcoder, sourceEncoder); } } diff --git a/library/src/main/java/com/bumptech/glide/load/engine/OriginalKey.java b/library/src/main/java/com/bumptech/glide/load/engine/OriginalKey.java new file mode 100644 index 00000000..d52e7b60 --- /dev/null +++ b/library/src/main/java/com/bumptech/glide/load/engine/OriginalKey.java @@ -0,0 +1,54 @@ +package com.bumptech.glide.load.engine; + +import com.bumptech.glide.load.Key; + +import java.io.UnsupportedEncodingException; +import java.security.MessageDigest; + +/** + * A class for keeping track of the cache key of the original data + any requested signature. + */ +class OriginalKey implements Key { + + private final String id; + private final Key signature; + + public OriginalKey(String id, Key signature) { + this.id = id; + this.signature = signature; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + OriginalKey that = (OriginalKey) o; + + if (!id.equals(that.id)) { + return false; + } + if (!signature.equals(that.signature)) { + return false; + } + + return true; + } + + @Override + public int hashCode() { + int result = id.hashCode(); + result = 31 * result + signature.hashCode(); + return result; + } + + @Override + public void updateDiskCacheKey(MessageDigest messageDigest) throws UnsupportedEncodingException { + messageDigest.update(id.getBytes(STRING_CHARSET_NAME)); + signature.updateDiskCacheKey(messageDigest); + } +} diff --git a/library/src/main/java/com/bumptech/glide/load/engine/cache/StringKey.java b/library/src/main/java/com/bumptech/glide/load/engine/cache/StringKey.java deleted file mode 100644 index a2f41e48..00000000 --- a/library/src/main/java/com/bumptech/glide/load/engine/cache/StringKey.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.bumptech.glide.load.engine.cache; - -import com.bumptech.glide.load.Key; - -import java.io.UnsupportedEncodingException; -import java.security.MessageDigest; - -/** - * A {@link com.bumptech.glide.load.Key} that wraps a single {@link java.lang.String}. - */ -public class StringKey implements Key { - private final String key; - - public StringKey(String key) { - this.key = key; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - StringKey stringKey = (StringKey) o; - - if (!key.equals(stringKey.key)) { - return false; - } - - return true; - } - - @Override - public int hashCode() { - return key.hashCode(); - } - - @Override - public String toString() { - return key; - } - - @Override - public void updateDiskCacheKey(MessageDigest messageDigest) throws UnsupportedEncodingException { - messageDigest.update(key.getBytes("UTF-8")); - } -} diff --git a/library/src/main/java/com/bumptech/glide/load/model/stream/MediaStoreStreamLoader.java b/library/src/main/java/com/bumptech/glide/load/model/stream/MediaStoreStreamLoader.java index f311a91e..e069fd77 100644 --- a/library/src/main/java/com/bumptech/glide/load/model/stream/MediaStoreStreamLoader.java +++ b/library/src/main/java/com/bumptech/glide/load/model/stream/MediaStoreStreamLoader.java @@ -19,22 +19,15 @@ import java.io.InputStream; public class MediaStoreStreamLoader implements ModelLoader<Uri, InputStream> { private final Context context; private final ModelLoader<Uri, InputStream> uriLoader; - private final String mimeType; - private final long dateModified; - private final int orientation; - public MediaStoreStreamLoader(Context context, ModelLoader<Uri, InputStream> uriLoader, String mimeType, - long dateModified, int orientation) { + public MediaStoreStreamLoader(Context context, ModelLoader<Uri, InputStream> uriLoader) { this.context = context; this.uriLoader = uriLoader; - this.mimeType = mimeType; - this.dateModified = dateModified; - this.orientation = orientation; } @Override public DataFetcher<InputStream> getResourceFetcher(Uri model, int width, int height) { return new MediaStoreThumbFetcher(context, model, uriLoader.getResourceFetcher(model, width, height), width, - height, mimeType, dateModified, orientation); + height); } } diff --git a/library/src/main/java/com/bumptech/glide/request/GenericRequest.java b/library/src/main/java/com/bumptech/glide/request/GenericRequest.java index 77a6da2a..58afc85a 100644 --- a/library/src/main/java/com/bumptech/glide/request/GenericRequest.java +++ b/library/src/main/java/com/bumptech/glide/request/GenericRequest.java @@ -5,6 +5,7 @@ import android.graphics.drawable.Drawable; import android.util.Log; import com.bumptech.glide.Priority; import com.bumptech.glide.load.Encoder; +import com.bumptech.glide.load.Key; import com.bumptech.glide.load.ResourceDecoder; import com.bumptech.glide.load.ResourceEncoder; import com.bumptech.glide.load.Transformation; @@ -58,6 +59,7 @@ public final class GenericRequest<A, T, Z, R> implements Request, SizeReadyCallb private final String tag = String.valueOf(hashCode()); + private Key signature; private int placeholderResourceId; private int errorResourceId; private Context context; @@ -89,6 +91,7 @@ public final class GenericRequest<A, T, Z, R> implements Request, SizeReadyCallb public static <A, T, Z, R> GenericRequest<A, T, Z, R> obtain( LoadProvider<A, T, Z, R> loadProvider, A model, + Key signature, Context context, Priority priority, Target<R> target, @@ -114,6 +117,7 @@ public final class GenericRequest<A, T, Z, R> implements Request, SizeReadyCallb } request.init(loadProvider, model, + signature, context, priority, target, @@ -159,6 +163,7 @@ public final class GenericRequest<A, T, Z, R> implements Request, SizeReadyCallb private void init( LoadProvider<A, T, Z, R> loadProvider, A model, + Key signature, Context context, Priority priority, Target<R> target, @@ -179,6 +184,7 @@ public final class GenericRequest<A, T, Z, R> implements Request, SizeReadyCallb DiskCacheStrategy diskCacheStrategy) { this.loadProvider = loadProvider; this.model = model; + this.signature = signature; this.context = context; this.priority = priority; this.target = target; @@ -421,7 +427,7 @@ public final class GenericRequest<A, T, Z, R> implements Request, SizeReadyCallb logV("finished setup for calling load in " + LogTime.getElapsedMillis(startTime)); } loadedFromMemoryCache = true; - loadStatus = engine.load(width, height, cacheDecoder, dataFetcher, sourceEncoder, decoder, + loadStatus = engine.load(signature, width, height, cacheDecoder, dataFetcher, sourceEncoder, decoder, transformation, encoder, transcoder, priority, isMemoryCacheable, diskCacheStrategy, this); loadedFromMemoryCache = resource != null; if (Log.isLoggable(TAG, Log.VERBOSE)) { diff --git a/library/src/main/java/com/bumptech/glide/signature/ApplicationVersionSignature.java b/library/src/main/java/com/bumptech/glide/signature/ApplicationVersionSignature.java new file mode 100644 index 00000000..f51736d0 --- /dev/null +++ b/library/src/main/java/com/bumptech/glide/signature/ApplicationVersionSignature.java @@ -0,0 +1,63 @@ +package com.bumptech.glide.signature; + +import android.content.Context; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import com.bumptech.glide.load.Key; + +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; + +/** + * A utility class for obtaining a {@link com.bumptech.glide.load.Key} signature containing the application version + * name using {@link android.content.pm.PackageInfo#versionCode}. + */ +public final class ApplicationVersionSignature { + private static final ConcurrentHashMap<String, Key> PACKAGE_NAME_TO_KEY = new ConcurrentHashMap<String, Key>(); + + /** + * Returns the signature {@link com.bumptech.glide.load.Key} for version code of the Application of the given + * Context. + */ + public static Key obtain(Context context) { + String packageName = context.getPackageName(); + Key result = PACKAGE_NAME_TO_KEY.get(packageName); + if (result == null) { + Key toAdd = obtainVersionSignature(context); + result = PACKAGE_NAME_TO_KEY.putIfAbsent(packageName, toAdd); + // There wasn't a previous mapping, so toAdd is now the Key. + if (result == null) { + result = toAdd; + } + } + + return result; + } + + // Visible for testing. + static void reset() { + PACKAGE_NAME_TO_KEY.clear(); + } + + private static Key obtainVersionSignature(Context context) { + PackageInfo pInfo = null; + try { + pInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0); + } catch (PackageManager.NameNotFoundException e) { + // Should never happen. + e.printStackTrace(); + } + + final String versionCode; + if (pInfo != null) { + versionCode = String.valueOf(pInfo.versionCode); + } else { + versionCode = UUID.randomUUID().toString(); + } + return new StringSignature(versionCode); + } + + private ApplicationVersionSignature() { + // Empty for visibility. + } +} diff --git a/library/src/main/java/com/bumptech/glide/signature/EmptySignature.java b/library/src/main/java/com/bumptech/glide/signature/EmptySignature.java new file mode 100644 index 00000000..c46c9149 --- /dev/null +++ b/library/src/main/java/com/bumptech/glide/signature/EmptySignature.java @@ -0,0 +1,26 @@ +package com.bumptech.glide.signature; + +import com.bumptech.glide.load.Key; + +import java.io.UnsupportedEncodingException; +import java.security.MessageDigest; + +/** + * An empty key that is always equal to all other empty keys. + */ +public final class EmptySignature implements Key { + private static final EmptySignature EMPTY_KEY = new EmptySignature(); + + public static EmptySignature obtain() { + return EMPTY_KEY; + } + + private EmptySignature() { + // Empty. + } + + @Override + public void updateDiskCacheKey(MessageDigest messageDigest) throws UnsupportedEncodingException { + // Do nothing. + } +} diff --git a/library/src/main/java/com/bumptech/glide/signature/MediaStoreSignature.java b/library/src/main/java/com/bumptech/glide/signature/MediaStoreSignature.java new file mode 100644 index 00000000..4774a69b --- /dev/null +++ b/library/src/main/java/com/bumptech/glide/signature/MediaStoreSignature.java @@ -0,0 +1,65 @@ +package com.bumptech.glide.signature; + +import com.bumptech.glide.load.Key; + +import java.io.UnsupportedEncodingException; +import java.nio.ByteBuffer; +import java.security.MessageDigest; + +/** + * A unique signature based on metadata data from the media store that detects common changes to media store files like + * edits, rotations, and temporary file replacement. + */ +public class MediaStoreSignature implements Key { + private final String mimeType; + private final long dateModified; + private final int orientation; + + public MediaStoreSignature(String mimeType, long dateModified, int orientation) { + this.mimeType = mimeType; + this.dateModified = dateModified; + this.orientation = orientation; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + MediaStoreSignature that = (MediaStoreSignature) o; + + if (dateModified != that.dateModified) { + return false; + } + if (orientation != that.orientation) { + return false; + } + if (mimeType != null ? !mimeType.equals(that.mimeType) : that.mimeType != null) { + return false; + } + + return true; + } + + @Override + public int hashCode() { + int result = mimeType != null ? mimeType.hashCode() : 0; + result = 31 * result + (int) (dateModified ^ (dateModified >>> 32)); + result = 31 * result + orientation; + return result; + } + + @Override + public void updateDiskCacheKey(MessageDigest messageDigest) throws UnsupportedEncodingException { + byte[] data = ByteBuffer.allocate(12) + .putLong(dateModified) + .putInt(orientation) + .array(); + messageDigest.update(data); + messageDigest.update(mimeType.getBytes(STRING_CHARSET_NAME)); + } +} diff --git a/library/src/main/java/com/bumptech/glide/signature/StringSignature.java b/library/src/main/java/com/bumptech/glide/signature/StringSignature.java new file mode 100644 index 00000000..a5fa2c9f --- /dev/null +++ b/library/src/main/java/com/bumptech/glide/signature/StringSignature.java @@ -0,0 +1,44 @@ +package com.bumptech.glide.signature; + +import com.bumptech.glide.load.Key; + +import java.io.UnsupportedEncodingException; +import java.security.MessageDigest; + +/** + * A unique Signature that wraps a String. + */ +public class StringSignature implements Key { + private final String signature; + + public StringSignature(String signature) { + if (signature == null) { + throw new NullPointerException("Signature cannot be null!"); + } + this.signature = signature; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + StringSignature that = (StringSignature) o; + + return signature.equals(that.signature); + } + + @Override + public int hashCode() { + return signature.hashCode(); + } + + @Override + public void updateDiskCacheKey(MessageDigest messageDigest) throws UnsupportedEncodingException { + messageDigest.update(signature.getBytes(STRING_CHARSET_NAME)); + } +} |