From c572847b4cf003bcd5070b5d0499342ac6827450 Mon Sep 17 00:00:00 2001 From: Sam Judd Date: Sun, 4 Aug 2013 12:34:38 -0700 Subject: [PATCH] Allow arbitrary transformations Also passes loaders all the way to image manager to decrease # of objects created for images in the memory or disk cache. --- library/src/com/bumptech/glide/Glide.java | 54 +++++++++-- .../glide/loader/image/BaseImageLoader.java | 95 ------------------- .../glide/loader/image/ImageLoader.java | 3 +- .../glide/loader/model/BaseModelLoader.java | 29 ------ .../glide/loader/model/FileLoader.java | 3 - .../glide/loader/model/ModelLoader.java | 6 -- .../glide/loader/model/ResourceLoader.java | 3 - .../glide/loader/model/StringLoader.java | 4 +- .../glide/loader/model/UriLoader.java | 10 +- .../glide/loader/model/VolleyModelLoader.java | 4 +- .../loader/transformation/CenterCrop.java | 15 +++ .../loader/transformation/FitCenter.java | 16 ++++ .../glide/loader/transformation/None.java | 15 +++ .../transformation/TransformationLoader.java | 19 ++++ .../glide/presenter/ImagePresenter.java | 25 ++++- .../bumptech/glide/resize/ImageManager.java | 28 +++--- .../glide/resize/loader/Approximate.java | 36 ------- .../bumptech/glide/resize/loader/AsIs.java | 27 ------ .../glide/resize/loader/CenterCrop.java | 29 ------ .../glide/resize/loader/FitCenter.java | 31 ------ .../resize/loader/ImageManagerLoader.java | 45 +++------ .../src/com/bumptech/glide/GlideTest.java | 38 ++++---- .../glide/loader/StringLoaderTest.java | 3 - .../bumptech/glide/loader/UriLoaderTest.java | 6 +- .../com/bumptech/flickr/FlickrPhotoGrid.java | 12 +-- 25 files changed, 190 insertions(+), 366 deletions(-) delete mode 100644 library/src/com/bumptech/glide/loader/image/BaseImageLoader.java delete mode 100644 library/src/com/bumptech/glide/loader/model/BaseModelLoader.java create mode 100644 library/src/com/bumptech/glide/loader/transformation/CenterCrop.java create mode 100644 library/src/com/bumptech/glide/loader/transformation/FitCenter.java create mode 100644 library/src/com/bumptech/glide/loader/transformation/None.java create mode 100644 library/src/com/bumptech/glide/loader/transformation/TransformationLoader.java delete mode 100644 library/src/com/bumptech/glide/resize/loader/Approximate.java delete mode 100644 library/src/com/bumptech/glide/resize/loader/AsIs.java delete mode 100644 library/src/com/bumptech/glide/resize/loader/CenterCrop.java delete mode 100644 library/src/com/bumptech/glide/resize/loader/FitCenter.java diff --git a/library/src/com/bumptech/glide/Glide.java b/library/src/com/bumptech/glide/Glide.java index 7a02a61aa0..0e0a4eeec9 100644 --- a/library/src/com/bumptech/glide/Glide.java +++ b/library/src/com/bumptech/glide/Glide.java @@ -15,14 +15,14 @@ import com.bumptech.glide.loader.model.StringLoader; import com.bumptech.glide.loader.model.UriLoader; import com.bumptech.glide.loader.model.UrlLoader; +import com.bumptech.glide.loader.transformation.CenterCrop; +import com.bumptech.glide.loader.transformation.FitCenter; +import com.bumptech.glide.loader.transformation.TransformationLoader; import com.bumptech.glide.presenter.ImagePresenter; import com.bumptech.glide.presenter.ImageReadyCallback; import com.bumptech.glide.resize.Downsampler; import com.bumptech.glide.resize.ImageManager; import com.bumptech.glide.resize.Transformation; -import com.bumptech.glide.resize.loader.Approximate; -import com.bumptech.glide.resize.loader.CenterCrop; -import com.bumptech.glide.resize.loader.FitCenter; import com.bumptech.glide.resize.loader.ImageManagerLoader; import java.io.File; @@ -338,6 +338,7 @@ public Request load(T model) { */ @SuppressWarnings("unused") //public api public static class Request { + private enum ResizeOption { APPROXIMATE, CENTER_CROP, @@ -353,8 +354,9 @@ private enum ResizeOption { private int animationId = -1; private int placeholderId = -1; private int errorId = -1; - private Transformation transformation = Transformation.NONE; + private Transformation transformation = null; private Downsampler downsampler = null; + private TransformationLoader transformationLoader = null; public Request(T model) { this.model = model; @@ -376,6 +378,7 @@ public Request(T model, ModelLoader modelLoader) { public Request centerCrop() { transformation = Transformation.CENTER_CROP; downsampler = Downsampler.AT_LEAST; + transformationLoader = null; return this; } @@ -388,6 +391,7 @@ public Request centerCrop() { public Request fitCenter() { transformation = Transformation.FIT_CENTER; downsampler = Downsampler.AT_LEAST; + transformationLoader = null; return this; } @@ -400,6 +404,7 @@ public Request fitCenter() { public Request approximate() { transformation = Transformation.NONE; downsampler = Downsampler.AT_LEAST; + transformationLoader = null; return this; } @@ -413,6 +418,7 @@ public Request approximate() { public Request asIs() { transformation = Transformation.NONE; downsampler = Downsampler.NONE; + transformationLoader = null; return this; } @@ -424,9 +430,18 @@ public Request asIs() { * @param transformation The transformation to use * @return This Request */ - public Request transform(Transformation transformation) { + public Request transform(final Transformation transformation) { this.transformation = transformation; downsampler = Downsampler.AT_LEAST; + transformationLoader = null; + + return this; + } + + public Request transform(TransformationLoader transformationLoader) { + this.transformationLoader = transformationLoader; + transformation = null; + downsampler = Downsampler.AT_LEAST; return this; } @@ -508,11 +523,13 @@ private ImagePresenter buildImagePresenter(ImageView imageView) { final Context context = imageView.getContext(); modelLoader = getFinalModelLoader(context); + transformationLoader = getFinalTransformationLoader(); ImagePresenter.Builder builder = new ImagePresenter.Builder() .setImageView(imageView) .setModelLoader(modelLoader) - .setImageLoader(new ImageManagerLoader(context, downsampler, transformation)); + .setImageLoader(new ImageManagerLoader(context, downsampler)) + .setTransformationLoader(transformationLoader); if (animationId != -1) { final Animation animation = AnimationUtils.loadAnimation(imageView.getContext(), animationId); @@ -533,7 +550,6 @@ public void onImageReady(ImageView view, boolean fromCache) { builder.setPlaceholderResource(placeholderId); } - if (errorId != -1) { builder.setErrorResource(errorId); } @@ -549,6 +565,27 @@ private ModelLoader getFinalModelLoader(Context context) { } } + private TransformationLoader getFinalTransformationLoader() { + if (transformationLoader != null) { + return transformationLoader; + } else { + return new TransformationLoader() { + @Override + public Transformation getTransformation(T model) { + return transformation; + } + }; + } + } + + private String getFinalTransformationId() { + if (transformationLoader != null) { + return transformationLoader.getClass().toString(); + } else { + return transformation.getId(); + } + } + private Downsampler getFinalDownsampler(ImageView imageView) { Downsampler result = downsampler; if (result == null) { @@ -562,6 +599,7 @@ private Downsampler getFinalDownsampler(ImageView imageView) { return result; } + private static Metadata getMetadataFrom(ImageView imageView) { return (Metadata) imageView.getTag(R.id.glide_metadata); } @@ -583,7 +621,7 @@ public Metadata(Request request) { modelClass = request.model.getClass(); modelLoaderClass = request.modelLoaderClass; downsamplerId = request.downsampler.getId(); - transformationId = request.transformation.getId(); + transformationId = request.getFinalTransformationId(); animationId = request.animationId; placeholderId = request.placeholderId; errorId = request.errorId; diff --git a/library/src/com/bumptech/glide/loader/image/BaseImageLoader.java b/library/src/com/bumptech/glide/loader/image/BaseImageLoader.java deleted file mode 100644 index 7ca05b914a..0000000000 --- a/library/src/com/bumptech/glide/loader/image/BaseImageLoader.java +++ /dev/null @@ -1,95 +0,0 @@ -package com.bumptech.glide.loader.image; - -import android.graphics.Bitmap; -import com.bumptech.glide.loader.stream.StreamLoader; - -import java.lang.ref.WeakReference; - - -/** - * A base class for {@link ImageLoader} that provides some lifecycle methods and prevents memory leaks by only providing - * subclasses with a weak reference to the calling {@link com.bumptech.glide.presenter.ImagePresenter}. - */ -public abstract class BaseImageLoader implements ImageLoader { - @Override - public final Object fetchImage(String id, StreamLoader streamLoader, int width, int height, ImageReadyCallback cb) { - doFetchImage(id, streamLoader, width, height, new InternalImageReadyCallback(cb, id)); - return cb; - } - - @Override - public void clear() { } - - /** - * The method where subclasses should actually begin any long running load for the given path and model. It is - * safe to strongly reference the given callback since that callback only weakly references the object that created - * it. Once a load completes or fails the given callback should be called to signal to the calling object that the - * image is ready. - * - * @see ImageLoader#fetchImage(String, com.bumptech.glide.loader.stream.StreamLoader, int, int, com.bumptech.glide.loader.image.ImageLoader.ImageReadyCallback) - * - * @param id A string id that uniquely identifies the image to be loaded. It may include the width and height, but - * is not required to do so - * @param streamLoader The {@link StreamLoader} that will be used to load the image if it is not cached - * @param width The width of the view where the image will be displayed - * @param height The height of the view where the image will be displayed - * @param cb The callback to call when the bitmap is loaded into memory, or when a load fails - */ - protected abstract void doFetchImage(String id, StreamLoader streamLoader, int width, int height, ImageReadyCallback cb); - - /** - * A lifecycle method called after the requesting object is notified that this loader has loaded a bitmap. Should be - * used to cleanup or update any data related to the completed load. Should not be used as a callback to change how - * an image is displayed. See {@link com.bumptech.glide.presenter.ImageReadyCallback} instead to make a visual change - * when a load completes. - * - * @param id The unique id of the image - * @param image The loaded image - * @param isUsed True iff the requesting object is going to display the image - */ - protected void onImageReady(String id, Bitmap image, boolean isUsed) { } - - /** - * A lifecycle method called after the requesting object is notified that this loader failed to load a Bitmap. - * Should be used to cleanup or update any data related to the failed load. - * - * @param e The exception that caused the failure, or null - * @param id The unique id of the image - * @return True iff this image loader has handled the exception and the cb should not be notified. - */ - @SuppressWarnings("unused") - protected boolean onImageLoadFailed(Exception e, String id) { - return false; - } - - protected class InternalImageReadyCallback implements ImageReadyCallback { - private final WeakReference cbRef; - private final String id; - - public InternalImageReadyCallback(ImageReadyCallback cb, String id) { - this.cbRef = new WeakReference(cb); - this.id = id; - } - - @Override - public final boolean onImageReady(Bitmap image) { - final ImageReadyCallback cb = cbRef.get(); - boolean result = false; - if (cb != null) { - result = cb.onImageReady(image); - BaseImageLoader.this.onImageReady(id, image, result); - } - return result; - } - - @Override - public void onException(Exception e) { - final ImageReadyCallback cb = cbRef.get(); - if (cb != null) { - if (!BaseImageLoader.this.onImageLoadFailed(e, id)) { - cb.onException(e); - } - } - } - } -} diff --git a/library/src/com/bumptech/glide/loader/image/ImageLoader.java b/library/src/com/bumptech/glide/loader/image/ImageLoader.java index f5cd9bbe28..d6f25d5743 100644 --- a/library/src/com/bumptech/glide/loader/image/ImageLoader.java +++ b/library/src/com/bumptech/glide/loader/image/ImageLoader.java @@ -2,6 +2,7 @@ import android.graphics.Bitmap; import com.bumptech.glide.loader.stream.StreamLoader; +import com.bumptech.glide.resize.Transformation; /** * An interface used by {@link com.bumptech.glide.presenter.ImagePresenter} to fetch a bitmap for a given id and @@ -44,7 +45,7 @@ public interface ImageReadyCallback { * * @return A reference to the fetch that must be retained by the calling object as long as the fetch is relevant */ - public Object fetchImage(String id, StreamLoader streamLoader, int width, int height, ImageReadyCallback cb); + public Object fetchImage(String id, StreamLoader streamLoader, Transformation transformation, int width, int height, ImageReadyCallback cb); /** * Called when the current image load does not need to continue and any corresponding cleanup to save cpu diff --git a/library/src/com/bumptech/glide/loader/model/BaseModelLoader.java b/library/src/com/bumptech/glide/loader/model/BaseModelLoader.java deleted file mode 100644 index 3782dd548d..0000000000 --- a/library/src/com/bumptech/glide/loader/model/BaseModelLoader.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.bumptech.glide.loader.model; - -import com.bumptech.glide.loader.stream.StreamLoader; - -/** - * A base class that handles canceling any existing {@link StreamLoader} when - * cleared - * - * @param The type of model for this loader - */ -public abstract class BaseModelLoader implements ModelLoader { - private StreamLoader current; - - @Override - public final StreamLoader getStreamLoader(T model, int width, int height) { - current = buildStreamLoader(model, width, height); - return current; - } - - protected abstract StreamLoader buildStreamLoader(T model, int width, int height); - - @Override - public void clear() { - if (current != null) { - current.cancel(); - current = null; - } - } -} diff --git a/library/src/com/bumptech/glide/loader/model/FileLoader.java b/library/src/com/bumptech/glide/loader/model/FileLoader.java index 776f4304a8..0b25b737ae 100644 --- a/library/src/com/bumptech/glide/loader/model/FileLoader.java +++ b/library/src/com/bumptech/glide/loader/model/FileLoader.java @@ -27,7 +27,4 @@ public String getId(File model) { //canonical is better, but also slower return model.getAbsolutePath(); } - - @Override - public void clear() { } } diff --git a/library/src/com/bumptech/glide/loader/model/ModelLoader.java b/library/src/com/bumptech/glide/loader/model/ModelLoader.java index 5061f90ba5..7aab16f144 100644 --- a/library/src/com/bumptech/glide/loader/model/ModelLoader.java +++ b/library/src/com/bumptech/glide/loader/model/ModelLoader.java @@ -43,10 +43,4 @@ public interface ModelLoader { * it does not have to. */ public String getId(T model); - - /** - * A method that allows the ModelLoader to cleanup any old or inprocess {@link StreamLoader}. Primarily oriented - * at allowing the model loader to call {@link com.bumptech.glide.loader.stream.StreamLoader#cancel()}; - */ - public void clear(); } diff --git a/library/src/com/bumptech/glide/loader/model/ResourceLoader.java b/library/src/com/bumptech/glide/loader/model/ResourceLoader.java index 6aa9a5cfaf..dd33f8fe63 100644 --- a/library/src/com/bumptech/glide/loader/model/ResourceLoader.java +++ b/library/src/com/bumptech/glide/loader/model/ResourceLoader.java @@ -26,7 +26,4 @@ public StreamLoader getStreamLoader(Integer model, int width, int height) { public String getId(Integer model) { return model.toString(); } - - @Override - public void clear() { } } diff --git a/library/src/com/bumptech/glide/loader/model/StringLoader.java b/library/src/com/bumptech/glide/loader/model/StringLoader.java index e3e70d8c47..4a98e28bc1 100644 --- a/library/src/com/bumptech/glide/loader/model/StringLoader.java +++ b/library/src/com/bumptech/glide/loader/model/StringLoader.java @@ -10,7 +10,7 @@ * A model loader for handling certain string models. Handles paths, urls, and any uri string with a scheme handled by * {@link android.content.ContentResolver#openInputStream(android.net.Uri)}. */ -public class StringLoader extends BaseModelLoader { +public class StringLoader implements ModelLoader { private final ModelLoader uriLoader; @@ -28,7 +28,7 @@ public StringLoader(ModelLoader uriLoader) { } @Override - protected StreamLoader buildStreamLoader(final String model, final int width, final int height) { + public StreamLoader getStreamLoader(final String model, final int width, final int height) { Uri uri = Uri.parse(model); final String scheme = uri.getScheme(); diff --git a/library/src/com/bumptech/glide/loader/model/UriLoader.java b/library/src/com/bumptech/glide/loader/model/UriLoader.java index 2362fac25a..92bc22821e 100644 --- a/library/src/com/bumptech/glide/loader/model/UriLoader.java +++ b/library/src/com/bumptech/glide/loader/model/UriLoader.java @@ -13,7 +13,7 @@ * A model loader for trying to load Uris. Capable of handling 'http', 'https', 'android.resource', 'content', and * 'file' schemes. Unsupported schemes will throw an exception in {@link #buildStreamLoader(android.net.Uri, int, int)}. */ -public class UriLoader extends BaseModelLoader { +public class UriLoader implements ModelLoader { private final Context context; private final ModelLoader urlLoader; @@ -32,7 +32,7 @@ public UriLoader(Context context, ModelLoader urlLoader) { } @Override - protected StreamLoader buildStreamLoader(Uri model, int width, int height) { + public StreamLoader getStreamLoader(Uri model, int width, int height) { final String scheme = model.getScheme(); StreamLoader result = null; @@ -58,12 +58,6 @@ public String getId(Uri model) { return model.toString(); } - @Override - public void clear() { - super.clear(); - urlLoader.clear(); - } - private boolean isLocalUri(String scheme) { return ContentResolver.SCHEME_FILE.equals(scheme) || ContentResolver.SCHEME_CONTENT.equals(scheme) diff --git a/library/src/com/bumptech/glide/loader/model/VolleyModelLoader.java b/library/src/com/bumptech/glide/loader/model/VolleyModelLoader.java index f6866d894f..29b7cf1d88 100644 --- a/library/src/com/bumptech/glide/loader/model/VolleyModelLoader.java +++ b/library/src/com/bumptech/glide/loader/model/VolleyModelLoader.java @@ -12,7 +12,7 @@ * A base ModelLoader for using Volley to fetch an image from a model that * can readily be converted into a url */ -public abstract class VolleyModelLoader extends BaseModelLoader { +public abstract class VolleyModelLoader implements ModelLoader { private final RequestQueue requestQueue; /** @@ -30,7 +30,7 @@ public VolleyModelLoader(RequestQueue requestQueue) { } @Override - protected StreamLoader buildStreamLoader(T model, int width, int height) { + public StreamLoader getStreamLoader(T model, int width, int height) { return new VolleyStreamLoader(requestQueue, getUrl(model, width, height), getRetryPolicy()); } diff --git a/library/src/com/bumptech/glide/loader/transformation/CenterCrop.java b/library/src/com/bumptech/glide/loader/transformation/CenterCrop.java new file mode 100644 index 0000000000..00fed1b0ad --- /dev/null +++ b/library/src/com/bumptech/glide/loader/transformation/CenterCrop.java @@ -0,0 +1,15 @@ +package com.bumptech.glide.loader.transformation; + +import com.bumptech.glide.resize.Transformation; + +/** + * Load image to exactly match the view in one dimension and then crop the image to fit the other dimension. + * + * @param The type of the model. Can be any type since the {@link Transformation is model/type agnostic}. + */ +public class CenterCrop implements TransformationLoader{ + @Override + public Transformation getTransformation(T model) { + return Transformation.CENTER_CROP; + } +} diff --git a/library/src/com/bumptech/glide/loader/transformation/FitCenter.java b/library/src/com/bumptech/glide/loader/transformation/FitCenter.java new file mode 100644 index 0000000000..c202de59c4 --- /dev/null +++ b/library/src/com/bumptech/glide/loader/transformation/FitCenter.java @@ -0,0 +1,16 @@ +package com.bumptech.glide.loader.transformation; + +import com.bumptech.glide.resize.Transformation; + +/** + * Load the image so that one dimension of the image exactly matches one of the given dimensions and the other dimension + * of the image is smaller than or equal to the other given dimension. + * + * @param The type of the model. Can be any type since the {@link Transformation is model/type agnostic}. + */ +public class FitCenter implements TransformationLoader { + @Override + public Transformation getTransformation(T model) { + return Transformation.FIT_CENTER; + } +} diff --git a/library/src/com/bumptech/glide/loader/transformation/None.java b/library/src/com/bumptech/glide/loader/transformation/None.java new file mode 100644 index 0000000000..e8dc50afec --- /dev/null +++ b/library/src/com/bumptech/glide/loader/transformation/None.java @@ -0,0 +1,15 @@ +package com.bumptech.glide.loader.transformation; + +import com.bumptech.glide.resize.Transformation; + +/** + * A loader that will always return a noop {@link Transformation} that does not change a bitmap. + * + * @param The model type, can be anything since the {@link Transformation} is type agnostic + */ +public class None implements TransformationLoader { + @Override + public Transformation getTransformation(T model) { + return Transformation.NONE; + } +} diff --git a/library/src/com/bumptech/glide/loader/transformation/TransformationLoader.java b/library/src/com/bumptech/glide/loader/transformation/TransformationLoader.java new file mode 100644 index 0000000000..8a4507c381 --- /dev/null +++ b/library/src/com/bumptech/glide/loader/transformation/TransformationLoader.java @@ -0,0 +1,19 @@ +package com.bumptech.glide.loader.transformation; + +import com.bumptech.glide.resize.Transformation; + +/** + * A class for loading a {@link Transformation} for a particular model. This allows things like rotating the image based + * on its exif data + * + * @param The type of the model to be loaded + */ +public interface TransformationLoader { + /** + * Get the {@link Transformation} for the model + * + * @param model The model + * @return A new or static (if the transformation is type/model agnostic) {@link Transformation} + */ + public Transformation getTransformation(T model); +} diff --git a/library/src/com/bumptech/glide/presenter/ImagePresenter.java b/library/src/com/bumptech/glide/presenter/ImagePresenter.java index 57499d2e6b..4d5e65b316 100644 --- a/library/src/com/bumptech/glide/presenter/ImagePresenter.java +++ b/library/src/com/bumptech/glide/presenter/ImagePresenter.java @@ -17,6 +17,9 @@ import com.bumptech.glide.loader.image.ImageLoader; import com.bumptech.glide.loader.model.ModelLoader; import com.bumptech.glide.loader.stream.StreamLoader; +import com.bumptech.glide.loader.transformation.None; +import com.bumptech.glide.loader.transformation.TransformationLoader; +import com.bumptech.glide.resize.Transformation; import com.bumptech.glide.util.Log; import java.lang.ref.WeakReference; @@ -34,7 +37,6 @@ */ public class ImagePresenter { - private final Drawable errorDrawable; /** * A builder for an {@link ImagePresenter}. @@ -70,6 +72,7 @@ public void onException(Exception e, T model, boolean isCurrent) { private ModelLoader modelLoader; private int errorResourceId; private Drawable errorDrawable; + private TransformationLoader transformationLoader; /** * Builds an ImagePresenter. @@ -95,6 +98,10 @@ public ImagePresenter build(){ throw new IllegalArgumentException("cannot create presenter without a model loader"); } + if (transformationLoader == null) { + transformationLoader = new None(); + } + return new ImagePresenter(this); } @@ -235,6 +242,11 @@ public Builder setExceptionHandler(ExceptionHandler exceptionHandler) { this.exceptionHandler = exceptionHandler; return this; } + + public Builder setTransformationLoader(TransformationLoader transformationLoader) { + this.transformationLoader = transformationLoader; + return this; + } } @SuppressWarnings("all") @@ -242,6 +254,8 @@ public Builder setExceptionHandler(ExceptionHandler exceptionHandler) { private final ModelLoader modelLoader; private final ImageLoader imageLoader; + private final TransformationLoader transformationLoader; + private final Drawable placeholderDrawable; private final ImageReadyCallback imageReadyCallback; private final ImagePresenterCoordinator coordinator; @@ -254,6 +268,7 @@ public Builder setExceptionHandler(ExceptionHandler exceptionHandler) { private boolean isImageSet = false; private boolean loadedFromCache = false; private final SizeDeterminer sizeDeterminer; + private final Drawable errorDrawable; /** * An interface used to coordinate multiple {@link ImagePresenter} objects acting on the same view @@ -309,6 +324,7 @@ public static ImagePresenter getCurrent(View imageView) { protected ImagePresenter(Builder builder) { this.imageView = builder.imageView; this.imageLoader = builder.imageLoader; + this.transformationLoader = builder.transformationLoader; final Resources res = imageView.getResources(); if (builder.placeholderResourceId != 0) { @@ -405,17 +421,16 @@ public void clear() { resetPlaceHolder(); currentModel = null; isImageSet = false; - modelLoader.clear(); imageLoader.clear(); } private void fetchImage(final T model, int width, int height, final int loadCount) { - modelLoader.clear(); imageLoader.clear(); - final StreamLoader streamLoader = modelLoader.getStreamLoader(model, width, height); final String id = modelLoader.getId(model); + final StreamLoader sl = modelLoader.getStreamLoader(model, width, height); + final Transformation t = transformationLoader.getTransformation(model); - imageToken = imageLoader.fetchImage(id, streamLoader, width, height, new ImageLoader.ImageReadyCallback() { + imageToken = imageLoader.fetchImage(id, sl, t, width, height, new ImageLoader.ImageReadyCallback() { @Override public boolean onImageReady(Bitmap image) { if (loadCount != currentCount || !canSetImage() || image == null) return false; diff --git a/library/src/com/bumptech/glide/resize/ImageManager.java b/library/src/com/bumptech/glide/resize/ImageManager.java index 4a3238521a..fb336b4a48 100644 --- a/library/src/com/bumptech/glide/resize/ImageManager.java +++ b/library/src/com/bumptech/glide/resize/ImageManager.java @@ -340,14 +340,15 @@ public void onImageRemoved(Bitmap removed) { }); } - public Object getImage(String id, StreamLoader streamLoader, int width, int height, Downsampler downsampler, Transformation transformation, LoadedCallback cb) { + public Object getImage(String id, StreamLoader streamLoader, Transformation transformation, Downsampler downsampler, int width, int height, LoadedCallback cb) { if (shutdown) return null; - final String key = getKey(id, downsampler, transformation, width, height); + + final String key = getKey(id, transformation.getId(), downsampler, width, height); ImageManagerJob job = null; if (!returnFromCache(key, cb)) { job = new ImageManagerJob(); - job.execute(key, streamLoader, width, height, downsampler, transformation, cb); + job.execute(key, streamLoader, transformation, downsampler, width, height, cb); } return job; } @@ -432,25 +433,25 @@ private boolean returnFromCache(String key, LoadedCallback cb) { return found; } - private class ImageManagerJob implements Runnable { - private StreamLoader streamLoader; - private String key; + private class ImageManagerJob implements Runnable { private LoadedCallback cb; private Future future = null; private volatile boolean cancelled = false; - private Transformation transformation; private Downsampler downsampler; private int width; private int height; + private String key; + private StreamLoader streamLoader = null; + private Transformation transformation; - public void execute(String key, StreamLoader streamLoader, int width, int height, Downsampler downsampler, Transformation transformation, LoadedCallback cb) { + public void execute(String key, StreamLoader streamLoader, Transformation transformation, Downsampler downsampler, int width, int height, LoadedCallback cb) { this.key = key; + this.streamLoader = streamLoader; + this.transformation = transformation; this.cb = cb; this.width = width; this.height = height; - this.streamLoader = streamLoader; this.downsampler = downsampler; - this.transformation = transformation; bgHandler.post(this); } @@ -460,6 +461,9 @@ public void cancel() { if (future != null) { future.cancel(false); } + if (streamLoader != null) { + streamLoader.cancel(); + } } @Override @@ -579,8 +583,8 @@ private void putInMemoryCache(String key, final Bitmap bitmap) { bitmapReferenceCounter.markPending(bitmap); } - private static String getKey(String id, Downsampler downsampler, Transformation transformation, int width, int height) { + private static String getKey(String id, String transformationId, Downsampler downsampler, int width, int height) { return String.valueOf(Util.hash(id.hashCode(), downsampler.getId().hashCode(), - transformation.getId().hashCode(), width, height)); + transformationId.hashCode(), width, height)); } } diff --git a/library/src/com/bumptech/glide/resize/loader/Approximate.java b/library/src/com/bumptech/glide/resize/loader/Approximate.java deleted file mode 100644 index aa02603227..0000000000 --- a/library/src/com/bumptech/glide/resize/loader/Approximate.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2012. Bump Technologies Inc. All Rights Reserved. - */ - -package com.bumptech.glide.resize.loader; - -import android.content.Context; -import android.graphics.Bitmap; -import com.bumptech.glide.loader.stream.StreamLoader; -import com.bumptech.glide.resize.Downsampler; -import com.bumptech.glide.resize.ImageManager; -import com.bumptech.glide.resize.LoadedCallback; -import com.bumptech.glide.resize.Transformation; - -/** - * Load an image at roughly the width and height of the view that will display it, maintaining its original aspect ratio - * - *

- * Should be used when the image is larger than the view that will display it and you don't want to alter the original - * aspect ratio. Can save a substantial amount of memory depending on the size discrepancy between the view and the - * image. - *

- * - * @see ImageManager#getImageApproximate(String, com.bumptech.glide.loader.stream.StreamLoader, int, int, com.bumptech.glide.resize.LoadedCallback) - */ -@SuppressWarnings("unused") -public class Approximate extends ImageManagerLoader { - - public Approximate(Context context) { - super(context, Downsampler.AT_LEAST, Transformation.NONE); - } - - public Approximate(ImageManager imageManager) { - super(imageManager, Downsampler.AT_LEAST, Transformation.NONE); - } -} diff --git a/library/src/com/bumptech/glide/resize/loader/AsIs.java b/library/src/com/bumptech/glide/resize/loader/AsIs.java deleted file mode 100644 index 5b9a20e552..0000000000 --- a/library/src/com/bumptech/glide/resize/loader/AsIs.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.bumptech.glide.resize.loader; - -import android.content.Context; -import com.bumptech.glide.resize.ImageManager; -import com.bumptech.glide.resize.Transformation; - -/** - * Load an image at its original dimensions. - * - *

Should be used when an image is exactly the same size as the view that will display it - * or you want to use some external process (like the view) to do the resizing for you. This class is usually less - * efficient than other implementations if the image is not exactly the size of the view - *

- * - * @see ImageManager#getImage(String, com.bumptech.glide.loader.stream.StreamLoader, com.bumptech.glide.resize.LoadedCallback) - */ -@SuppressWarnings("unused") -public class AsIs extends ImageManagerLoader { - - public AsIs(Context context) { - super(context, Transformation.CENTER_CROP); - } - - public AsIs(ImageManager imageManager) { - super(imageManager, Transformation.CENTER_CROP); - } -} diff --git a/library/src/com/bumptech/glide/resize/loader/CenterCrop.java b/library/src/com/bumptech/glide/resize/loader/CenterCrop.java deleted file mode 100644 index afc82f01ab..0000000000 --- a/library/src/com/bumptech/glide/resize/loader/CenterCrop.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2012. Bump Technologies Inc. All Rights Reserved. - */ - -package com.bumptech.glide.resize.loader; - -import android.content.Context; -import android.graphics.Bitmap; -import com.bumptech.glide.loader.stream.StreamLoader; -import com.bumptech.glide.resize.ImageManager; -import com.bumptech.glide.resize.LoadedCallback; -import com.bumptech.glide.resize.Transformation; - -/** - * Load image to exactly match the view in one dimension and then crop the image to fit the other dimension. - * - * @see ImageManager#centerCrop(String, com.bumptech.glide.loader.stream.StreamLoader, int, int, com.bumptech.glide.resize.LoadedCallback) - */ -@SuppressWarnings("unused") -public class CenterCrop extends ImageManagerLoader { - - public CenterCrop(Context context) { - super(context, Transformation.CENTER_CROP); - } - - public CenterCrop(ImageManager imageManager) { - super(imageManager, Transformation.CENTER_CROP); - } -} diff --git a/library/src/com/bumptech/glide/resize/loader/FitCenter.java b/library/src/com/bumptech/glide/resize/loader/FitCenter.java deleted file mode 100644 index 25c31e772c..0000000000 --- a/library/src/com/bumptech/glide/resize/loader/FitCenter.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2012. Bump Technologies Inc. All Rights Reserved. - */ - -package com.bumptech.glide.resize.loader; - -import android.content.Context; -import android.graphics.Bitmap; -import com.bumptech.glide.loader.stream.StreamLoader; -import com.bumptech.glide.resize.Downsampler; -import com.bumptech.glide.resize.ImageManager; -import com.bumptech.glide.resize.LoadedCallback; -import com.bumptech.glide.resize.Transformation; - -/** - * Load the image so that one dimension of the image exactly matches one of the given dimensions and the other dimension - * of the image is smaller than or equal to the other given dimension. - * - * @see ImageManager#fitCenter(String, com.bumptech.glide.loader.stream.StreamLoader, int, int, com.bumptech.glide.resize.LoadedCallback) - */ -@SuppressWarnings("Unused") -public class FitCenter extends ImageManagerLoader { - - public FitCenter(Context context) { - super(context, Transformation.FIT_CENTER); - } - - public FitCenter(ImageManager imageManager) { - super(imageManager, Transformation.FIT_CENTER); - } -} diff --git a/library/src/com/bumptech/glide/resize/loader/ImageManagerLoader.java b/library/src/com/bumptech/glide/resize/loader/ImageManagerLoader.java index a0aa4e378c..ffe07523a5 100644 --- a/library/src/com/bumptech/glide/resize/loader/ImageManagerLoader.java +++ b/library/src/com/bumptech/glide/resize/loader/ImageManagerLoader.java @@ -3,7 +3,7 @@ import android.content.Context; import android.graphics.Bitmap; import com.bumptech.glide.Glide; -import com.bumptech.glide.loader.image.BaseImageLoader; +import com.bumptech.glide.loader.image.ImageLoader; import com.bumptech.glide.loader.stream.StreamLoader; import com.bumptech.glide.resize.Downsampler; import com.bumptech.glide.resize.ImageManager; @@ -16,58 +16,41 @@ * A base class for loaders that user ImageManager. Primarily responsible for keeping track of bitmaps for recycling * purposes. */ -public class ImageManagerLoader extends BaseImageLoader { +public class ImageManagerLoader implements ImageLoader { protected final ImageManager imageManager; - private final Transformation transformation; private final Downsampler downsampler; private Bitmap acquired; private Object loadToken; - public ImageManagerLoader(Context context, Transformation transformation) { - this(context, Downsampler.AT_LEAST, transformation); + public ImageManagerLoader(Context context) { + this(context, Downsampler.AT_LEAST); } - public ImageManagerLoader(Context context, Downsampler downsampler, Transformation transformation) { - this(Glide.get().getImageManager(context), downsampler, transformation); + public ImageManagerLoader(ImageManager imageManager) { + this(imageManager, Downsampler.AT_LEAST); } - public ImageManagerLoader(ImageManager imageManager, Transformation transformation) { - this(imageManager, Downsampler.AT_LEAST, transformation); + public ImageManagerLoader(Context context, Downsampler downsampler) { + this(Glide.get().getImageManager(context), downsampler); } - public ImageManagerLoader(ImageManager imageManager, Downsampler downsampler, Transformation transformation) { + public ImageManagerLoader(ImageManager imageManager, Downsampler downsampler) { this.imageManager = imageManager; this.downsampler = downsampler; - this.transformation = transformation; } @Override - protected final void doFetchImage(String id, StreamLoader streamLoader, int width, int height, ImageReadyCallback cb) { + public Object fetchImage(String id, StreamLoader streamLoader, Transformation transformation, int width, int height, final ImageReadyCallback cb) { if (!isHandled(width, height)) { throw new IllegalArgumentException(getClass() + " cannot handle width=" + width + " and/or height =" + height); } - loadToken = loadFromImageManager(id, streamLoader, width, height, cb); - } + loadToken = imageManager.getImage(id, streamLoader, transformation, downsampler, width, height, new LoadedCallback() { - /** - * An abstract method to make a specific resize call to the {@link ImageManager} - * - * @param id A string id that uniquely identifies the image to be loaded. It may include the width and height, but - * is not required to do so - * @param streamLoader The {@link StreamLoader} that will be used to load the image if it is not cached - * @param width The width of the view where the image will be displayed - * @param height The height of the view where the image will be displayed - * @param cb The callback to call when the bitmap is loaded into memory, or when a load fails - * - * @return A reference to the fetch that must be retained by the calling object as long as the fetch is relevant - */ - protected Object loadFromImageManager(String id, StreamLoader streamLoader, int width, int height, final ImageReadyCallback cb) { - return imageManager.getImage(id, streamLoader, width, height, downsampler, transformation, new LoadedCallback() { @Override public void onLoadCompleted(Bitmap loaded) { - cb.onImageReady(loaded); + onImageReady(loaded, cb.onImageReady(loaded)); } @Override @@ -75,10 +58,10 @@ public void onLoadFailed(Exception e) { cb.onException(e); } }); + return loadToken; } - @Override - protected void onImageReady(String id, Bitmap image, boolean isUsed) { + protected void onImageReady(Bitmap image, boolean isUsed) { if (isUsed) { releaseAcquired(); imageManager.acquireBitmap(image); diff --git a/library/tests/src/com/bumptech/glide/GlideTest.java b/library/tests/src/com/bumptech/glide/GlideTest.java index e770b09193..246f2f88c7 100644 --- a/library/tests/src/com/bumptech/glide/GlideTest.java +++ b/library/tests/src/com/bumptech/glide/GlideTest.java @@ -45,7 +45,7 @@ private void checkImagePresenter(Object model) { } private ImagePresenter getImagePresenterFromView() { - return (ImagePresenter) imageView.getTag(R.id.image_presenter_id); + return (ImagePresenter) imageView.getTag(); } public void testFileDefaultLoader() { @@ -103,15 +103,15 @@ public void testCanHandleWrapContent() { ViewGroup.LayoutParams.WRAP_CONTENT)); Glide.load("fake").into(imageView); - assertNotNull(ImagePresenter.getCurrent(imageView)); + assertNotNull(getImagePresenterFromView()); } public void testDifferentModlsReplacesPresenters() { Glide.load("fake").into(imageView); - ImagePresenter first = ImagePresenter.getCurrent(imageView); + ImagePresenter first = getImagePresenterFromView(); Glide.load(4).into(imageView); - ImagePresenter second = ImagePresenter.getCurrent(imageView); + ImagePresenter second = getImagePresenterFromView(); assertNotSame(first, second); } @@ -122,7 +122,7 @@ public void testDifferentModelLoadersReplacesPresenter() { public StreamLoader getStreamLoader(Object model, int width, int height) { return new StreamLoader() { @Override - public void loadStream(StreamReadyCallback cb) { + public void loadStream(Object t, StreamReadyCallback cb) { } @Override @@ -136,19 +136,16 @@ public String getId(Object model) { return String.valueOf(model.hashCode()); } - @Override - public void clear() { - } }).load(new Object()).into(imageView); - ImagePresenter first = ImagePresenter.getCurrent(imageView); + ImagePresenter first = getImagePresenterFromView(); Glide.using(new ModelLoader() { @Override public StreamLoader getStreamLoader(Object model, int width, int height) { return new StreamLoader() { @Override - public void loadStream(StreamReadyCallback cb) { + public void loadStream(Object object, StreamReadyCallback cb) { } @Override @@ -162,12 +159,9 @@ public String getId(Object model) { return String.valueOf(model.hashCode()); } - @Override - public void clear() { - } }).load(new Object()).into(imageView); - ImagePresenter second = ImagePresenter.getCurrent(imageView); + ImagePresenter second = getImagePresenterFromView(); assertNotSame(first, second); } @@ -175,10 +169,10 @@ public void clear() { public void testDifferentImageLoadersReplacesPresenter() { final File file = new File("fake"); Glide.load(file).centerCrop().into(imageView); - ImagePresenter first = ImagePresenter.getCurrent(imageView); + ImagePresenter first = getImagePresenterFromView(); Glide.load(file).into(imageView); - ImagePresenter second = ImagePresenter.getCurrent(imageView); + ImagePresenter second = getImagePresenterFromView(); assertNotSame(first, second); } @@ -186,10 +180,10 @@ public void testDifferentImageLoadersReplacesPresenter() { public void testDifferentPlaceholdersReplacesPresenter() { final File file = new File("fake"); Glide.load(file).placeholder(com.bumptech.glide.tests.R.raw.ic_launcher).into(imageView); - ImagePresenter first = ImagePresenter.getCurrent(imageView); + ImagePresenter first = getImagePresenterFromView(); Glide.load(file).into(imageView); - ImagePresenter second = ImagePresenter.getCurrent(imageView); + ImagePresenter second = getImagePresenterFromView(); assertNotSame(first, second); } @@ -197,10 +191,10 @@ public void testDifferentPlaceholdersReplacesPresenter() { public void testDifferentAnimationsReplacesPresenter() { final File file = new File("fake"); Glide.load(file).animate(android.R.anim.fade_in).into(imageView); - ImagePresenter first = ImagePresenter.getCurrent(imageView); + ImagePresenter first = getImagePresenterFromView(); Glide.load(file).animate(android.R.anim.fade_out).into(imageView); - ImagePresenter second = ImagePresenter.getCurrent(imageView); + ImagePresenter second = getImagePresenterFromView(); assertNotSame(first, second); } @@ -208,10 +202,10 @@ public void testDifferentAnimationsReplacesPresenter() { public void testDifferentErrorIdsReplacesPresenter() { final File file = new File("fake"); Glide.load(file).error(com.bumptech.glide.tests.R.raw.ic_launcher).into(imageView); - ImagePresenter first = ImagePresenter.getCurrent(imageView); + ImagePresenter first = getImagePresenterFromView(); Glide.load(file).error(android.R.drawable.btn_star).into(imageView); - ImagePresenter second = ImagePresenter.getCurrent(imageView); + ImagePresenter second = getImagePresenterFromView(); assertNotSame(first, second); } diff --git a/library/tests/src/com/bumptech/glide/loader/StringLoaderTest.java b/library/tests/src/com/bumptech/glide/loader/StringLoaderTest.java index 019d3239a4..b4b00f796c 100644 --- a/library/tests/src/com/bumptech/glide/loader/StringLoaderTest.java +++ b/library/tests/src/com/bumptech/glide/loader/StringLoaderTest.java @@ -39,9 +39,6 @@ public String getId(Uri model) { return null; } - @Override - public void clear() { - } }; stringLoader = new StringLoader(uriLoader); diff --git a/library/tests/src/com/bumptech/glide/loader/UriLoaderTest.java b/library/tests/src/com/bumptech/glide/loader/UriLoaderTest.java index 1162e57616..fa562892f6 100644 --- a/library/tests/src/com/bumptech/glide/loader/UriLoaderTest.java +++ b/library/tests/src/com/bumptech/glide/loader/UriLoaderTest.java @@ -29,7 +29,7 @@ protected void setUp() throws Exception { urlLoader = new StreamLoader() { @Override - public void loadStream(StreamReadyCallback cb) { + public void loadStream(Object t, StreamReadyCallback cb) { } @Override @@ -46,10 +46,6 @@ public StreamLoader getStreamLoader(URL model, int width, int height) { public String getId(URL model) { return null; } - - @Override - public void clear() { - } }); } diff --git a/samples/flickr/src/com/bumptech/flickr/FlickrPhotoGrid.java b/samples/flickr/src/com/bumptech/flickr/FlickrPhotoGrid.java index a12824dd7e..85d56799f1 100644 --- a/samples/flickr/src/com/bumptech/flickr/FlickrPhotoGrid.java +++ b/samples/flickr/src/com/bumptech/flickr/FlickrPhotoGrid.java @@ -12,15 +12,10 @@ import android.widget.ImageView; import com.actionbarsherlock.app.SherlockFragment; import com.bumptech.flickr.api.Photo; +import com.bumptech.glide.loader.transformation.CenterCrop; import com.bumptech.glide.presenter.ImagePresenter; import com.bumptech.glide.presenter.ImageReadyCallback; -<<<<<<< HEAD -import com.bumptech.glide.resize.Downsampler; -import com.bumptech.glide.resize.Transformation; -import com.bumptech.glide.resize.loader.CenterCrop; -======= -import com.bumptech.glide.resize.loader.ImageManagerLoader; ->>>>>>> 765fdbe... Should have been in go to just image manager loader +import com.bumptech.glide.resize.loader.Approximate; import java.io.File; import java.util.ArrayList; @@ -119,7 +114,8 @@ public View getView(int position, View view, ViewGroup container) { imagePresenter = new ImagePresenter.Builder() .setImageView(imageView) .setModelLoader(new FlickrModelLoader(context)) - .setImageLoader(new CenterCrop(context)) + .setImageLoader(new Approximate(context)) + .setTransformationLoader(new CenterCrop()) .setImageReadyCallback(new ImageReadyCallback() { @Override public void onImageReady(ImageView view, boolean fromCache) {