From 896af010afa2c88aa6b63fc80c1a412357caed97 Mon Sep 17 00:00:00 2001 From: Sam Judd Date: Wed, 19 Mar 2014 07:35:04 -0700 Subject: [PATCH] Handle videos and images in one request. --- library/src/com/bumptech/glide/Glide.java | 579 ++++++++---------- .../loader/bitmap/BaseBitmapLoadFactory.java | 46 +- .../bitmap/model/GenericLoaderFactory.java | 5 +- .../glide/loader/bitmap/model/UriLoader.java | 6 +- .../glide/resize/BaseBitmapLoadTask.java | 61 +- .../src/com/bumptech/glide/GlideTest.java | 1 - .../com/bumptech/glide/ListPreloaderTest.java | 1 - .../samples/flickr/FlickrModelLoader.java | 2 +- .../glide/samples/flickr/FlickrPhotoGrid.java | 2 +- .../samples/flickr/FlickrSearchActivity.java | 4 +- 10 files changed, 347 insertions(+), 360 deletions(-) diff --git a/library/src/com/bumptech/glide/Glide.java b/library/src/com/bumptech/glide/Glide.java index b094d824f..3c4f08ce0 100644 --- a/library/src/com/bumptech/glide/Glide.java +++ b/library/src/com/bumptech/glide/Glide.java @@ -14,7 +14,6 @@ import com.bumptech.glide.loader.bitmap.model.file_descriptor.FileDescriptorMode import com.bumptech.glide.loader.bitmap.model.file_descriptor.FileDescriptorResourceLoader; import com.bumptech.glide.loader.bitmap.model.file_descriptor.FileDescriptorStringLoader; import com.bumptech.glide.loader.bitmap.model.file_descriptor.FileDescriptorUriLoader; -import com.bumptech.glide.loader.bitmap.model.stream.BaseUrlLoader; import com.bumptech.glide.loader.bitmap.model.stream.StreamResourceLoader; import com.bumptech.glide.loader.bitmap.model.stream.StreamFileLoader; import com.bumptech.glide.loader.bitmap.model.stream.StreamModelLoader; @@ -25,7 +24,6 @@ import com.bumptech.glide.loader.image.ImageManagerLoader; import com.bumptech.glide.loader.bitmap.model.GenericLoaderFactory; import com.bumptech.glide.loader.bitmap.model.ModelLoader; import com.bumptech.glide.loader.bitmap.model.ModelLoaderFactory; -import com.bumptech.glide.loader.bitmap.resource.ResourceFetcher; import com.bumptech.glide.loader.bitmap.transformation.CenterCrop; import com.bumptech.glide.loader.bitmap.transformation.FitCenter; import com.bumptech.glide.loader.bitmap.transformation.MultiTransformationLoader; @@ -49,7 +47,7 @@ import java.util.Map; import java.util.WeakHashMap; /** - * A singleton to present a simple static interface for Glide {@link Glide.Request} and to create and manage an + * A singleton to present a simple static interface for Glide {@link GenericRequest} and to create and manage an * {@link ImageLoader} and {@link ModelLoaderFactory}s. This class provides most of the functionality of * {@link ImagePresenter} with a simpler but less efficient interface. For more complicated cases it may be worth * considering using {@link ImagePresenter} and {@link com.bumptech.glide.presenter.ImagePresenter.Builder} directly. @@ -83,7 +81,7 @@ public class Glide { * For example: *
          * 
-         *     public void onException(Exception e, T model, Target target) {
+         *     public void onException(Exception e, ModelType model, Target target) {
          *         target.setPlaceholder(R.drawable.a_specific_error_for_my_exception);
          *         Glide.load(model).into(target);
          *     }
@@ -122,68 +120,21 @@ public class Glide {
     }
 
     protected Glide() {
-        loaderFactory.register(File.class, ParcelFileDescriptor.class, new FileDescriptorFileLoader.Factory());
-        loaderFactory.register(File.class, InputStream.class, new StreamFileLoader.Factory());
-        loaderFactory.register(Integer.class, ParcelFileDescriptor.class, new FileDescriptorResourceLoader.Factory());
-        loaderFactory.register(Integer.class, InputStream.class, new StreamResourceLoader.Factory());
-        loaderFactory.register(String.class, ParcelFileDescriptor.class, new FileDescriptorStringLoader.Factory());
-        loaderFactory.register(String.class, InputStream.class, new StreamStringLoader.Factory());
-        loaderFactory.register(Uri.class, ParcelFileDescriptor.class, new FileDescriptorUriLoader.Factory());
-        loaderFactory.register(Uri.class, InputStream.class, new StreamUriLoader.Factory());
-        loaderFactory.register(URL.class, ParcelFileDescriptor.class, new ModelLoaderFactory() {
-            @Override
-            public ModelLoader build(Context context, GenericLoaderFactory factories) {
-                throw new IllegalArgumentException("No ModelLoaderFactory for urls and file descriptors registered " +
-                        "with Glide");
-            }
-
-            @Override
-            public Class> loaderClass() {
-                throw new IllegalArgumentException("No ModelLoaderFactory for urls and file descriptors registered " +
-                        "with Glide");
-            }
-
-            @Override
-            public void teardown() {
-            }
-        });
+        register(File.class, ParcelFileDescriptor.class, new FileDescriptorFileLoader.Factory());
+        register(File.class, InputStream.class, new StreamFileLoader.Factory());
+        register(Integer.class, ParcelFileDescriptor.class, new FileDescriptorResourceLoader.Factory());
+        register(Integer.class, InputStream.class, new StreamResourceLoader.Factory());
+        register(String.class, ParcelFileDescriptor.class, new FileDescriptorStringLoader.Factory());
+        register(String.class, InputStream.class, new StreamStringLoader.Factory());
+        register(Uri.class, ParcelFileDescriptor.class, new FileDescriptorUriLoader.Factory());
+        register(Uri.class, InputStream.class, new StreamUriLoader.Factory());
         try {
             Class.forName("com.bumptech.glide.volley.VolleyUrlLoader$Factory");
-            loaderFactory.register(URL.class, InputStream.class, new VolleyUrlLoader.Factory());
+            register(URL.class, InputStream.class, new VolleyUrlLoader.Factory());
         } catch (ClassNotFoundException e) {
             if (Log.isLoggable(TAG, Log.DEBUG)) {
                 Log.d(TAG, "Volley not found, missing url loader");
             }
-            loaderFactory.register(URL.class, InputStream.class, new ModelLoaderFactory() {
-                ModelLoader errorUrlLoader = new ModelLoader() {
-
-                    @Override
-                    public ResourceFetcher getResourceFetcher(URL model, int width, int height) {
-                        throw new IllegalArgumentException("No ModelLoaderFactory for urls and InputStreams " +
-                                "registered with Glide");
-                    }
-
-                    @Override
-                    public String getId(URL model) {
-                        throw new IllegalArgumentException("No ModelLoaderFactory for urls and InputStreams " +
-                                "registered with Glide");
-                    }
-                };
-
-                @Override
-                public ModelLoader build(Context context, GenericLoaderFactory factories) {
-                    return errorUrlLoader;
-                }
-
-                @Override @SuppressWarnings("unchecked")
-                public Class> loaderClass() {
-                    return (Class>) errorUrlLoader.getClass();
-                }
-
-                @Override
-                public void teardown() {
-                }
-            });
         }
     }
 
@@ -207,7 +158,7 @@ public class Glide {
      * Use to check whether or not an {@link ImageManager} has been set yet. Can be used in
      * {@link android.app.Activity#onCreate(android.os.Bundle) Activity.onCreate} along with
      * {@link #setImageManager(com.bumptech.glide.resize.ImageManager.Builder) setImageManager} to set an
-     * {@link ImageManager} with custom options for use with {@link com.bumptech.glide.Glide.Request} and/or as an
+     * {@link ImageManager} with custom options for use with {@link GenericRequest} and/or as an
      * easily accessible singleton.
      *
      * @return true iff an {@link ImageManager} is currently set
@@ -217,7 +168,7 @@ public class Glide {
     }
 
     /**
-     * Set the {@link ImageManager} to use with {@link Glide.Request}.
+     * Set the {@link ImageManager} to use with {@link GenericRequest}.
      *
      * @see #setImageManager(com.bumptech.glide.resize.ImageManager)
      *
@@ -228,7 +179,7 @@ public class Glide {
     }
 
     /**
-     * Set the {@link ImageManager} to use with {@link Glide.Request} Replaces the current
+     * Set the {@link ImageManager} to use with {@link GenericRequest} Replaces the current
      * {@link ImageManager} if one has already been set.
      *
      * @see #isImageManagerSet()
@@ -242,8 +193,8 @@ public class Glide {
     /**
      * Use the given factory to build a {@link ModelLoader} for models of the given class. Generally the best use of
      * this method is to replace one of the default factories or add an implementation for other similar low level
-     * models. Typically the {@link Glide#using(ModelLoader)} syntax is preferred
-     * because it directly links the model with the ModelLoader being used to load it.
+     * models. Typically the {@link Glide#using(StreamModelLoader)} or {@link Glide#using(FileDescriptorModelLoader)}
+     * syntax is preferred because it directly links the model with the ModelLoader being used to load it.
      *
      * 

* Note - If a factory already exists for the given class, it will be replaced. If that factory is not being @@ -256,12 +207,17 @@ public class Glide { * retained statically. *

* - * @param clazz The class - * @param factory The factory to use - * @param The type of the model + * @see #using(FileDescriptorModelLoader) + * @see #using(StreamModelLoader) + * + * @param modelClass The model class. + * @param resourceClass The resource class the model loader will translate the model type into. + * @param factory The factory to use. + * @param The type of the model. + * @param the type of the resource. */ - public void register(Class clazz, ModelLoaderFactory factory) { - ModelLoaderFactory removed = loaderFactory.register(clazz, InputStream.class, factory); + public void register(Class modelClass, Class resourceClass, ModelLoaderFactory factory) { + ModelLoaderFactory removed = loaderFactory.register(modelClass, resourceClass, factory); if (removed != null) { removed.teardown(); } @@ -307,134 +263,54 @@ public class Glide { } /** - * Set the {@link ModelLoaderFactory} and therefore the model type to use for a new load. - * - *

- * Note - You can use this method to set a {@link ModelLoaderFactory} for models that don't have a default - * {@link ModelLoader}/{@link ModelLoaderFactory}. You can also optionally use this method to override the - * default {@link ModelLoader} for a model for which there is a default. If you would like to permanently - * use this factory for all model loads of the this factory's type, see - * {@link #register(Class, ModelLoaderFactory)}. - *

- * - *

- * Note - If you have the ability to fetch different sized images for a given model, it is most efficient to - * supply a custom {@link ModelLoaderFactory} here to do so, even if a default exists. Fetching a smaller image - * means less bandwidth, battery, and memory usage as well as faster image loads. To simply build a url to - * download an image using the width and the height of the target, consider passing in a factory for a subclass - * of {@link BaseUrlLoader} - *

- * - * - * @param factory The {@link ModelLoaderFactory} to use to load an image from a given model - * @param The type of the model to load using this factory - * @return A {@link ModelRequest} to set the specific model to load - */ - public static ModelRequest using(ModelLoaderFactory factory) { - return new ModelRequest(factory); - } - - /** - * Set the {@link ModelLoader} and therefore the model type to use for a new load. - * - * @see #using(ModelLoaderFactory) + * 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. * - * @param modelLoader The model loader to use - * @param The type of the model to load using this loader - * @param the type of resource the model loader can translate from a given model. - * @return A {@link ModelRequest} to set the specific model to load + * @param modelLoader The model loader to use. + * @param The type of the model. + * @return A new {@link ImageModelRequest}. */ - public static ModelRequest using(final ModelLoader modelLoader) { - return new ModelRequest(new ModelLoaderFactory() { - - @Override - public ModelLoader build(Context context, GenericLoaderFactory factories) { - return modelLoader; - } - - @SuppressWarnings("unchecked") - @Override - public Class> loaderClass() { - return (Class>) modelLoader.getClass(); - } - - @Override - public void teardown() { } - }); + public static ImageModelRequest using(final StreamModelLoader modelLoader) { + return new ImageModelRequest(modelLoaderToFactory(modelLoader)); } /** - * Set the {@link ModelLoader} to use for for a new load where the model loader translates from a model to an - * {@link InputStream} resource. + * 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. * - * @param streamModelLoader The model loader to use. + * @param modelLoader The model loader to use. * @param The type of the model. - * @return A new {@link StreamModelRequest}. + * @return A new {@link VideoModelRequest}. */ - public static StreamModelRequest using(final StreamModelLoader streamModelLoader) { - return new StreamModelRequest(new ModelLoaderFactory() { - @Override - public ModelLoader build(Context context, GenericLoaderFactory factories) { - return streamModelLoader; - } - - @SuppressWarnings("unchecked") - @Override - public Class> loaderClass() { - return (Class>) streamModelLoader.getClass(); - } - - @Override - public void teardown() { } - }); + public static VideoModelRequest using(final FileDescriptorModelLoader modelLoader) { + return new VideoModelRequest(modelLoaderToFactory(modelLoader)); } - public static FileDescriptorModelRequest using(final FileDescriptorModelLoader loader) { - return new FileDescriptorModelRequest(new ModelLoaderFactory() { - @Override - public ModelLoader build(Context context, GenericLoaderFactory factories) { - return loader; - } - - @SuppressWarnings("unchecked") - @Override - public Class> loaderClass() { - return (Class>) loader.getClass(); - } - - @Override - public void teardown() { - } - }); - } - /** * Use the {@link ModelLoaderFactory} currently registered for {@link String} to load the image represented by the * given {@link String}. Defaults to {@link StreamStringLoader.Factory} and {@link StreamStringLoader} to load the given model. * - * @see #using(ModelLoaderFactory) - * @see ModelRequest#load(String) + * @see #using(StreamModelLoader) * * @param string The string representing the image. Must be either a path, or a uri handled by {@link StreamUriLoader} - * @return A {@link Request} to set options for the load and ultimately the target to load the model into + * @return A {@link GenericRequest} to set options for the load and ultimately the target to load the model into */ - public static StreamRequest load(String string) { - return new StreamRequest(string); + public static Request load(String string) { + return new Request(string); } /** * Use the {@link ModelLoaderFactory} currently registered for {@link Uri} to load the image at the given uri. * Defaults to {@link StreamUriLoader.Factory} and {@link StreamUriLoader}. * - * @see #using(ModelLoaderFactory) - * @see ModelRequest#load(android.net.Uri) + * @see #using(StreamModelLoader) * * @param uri The uri representing the image. Must be a uri handled by {@link StreamUriLoader} - * @return A {@link Request} to set options for the load and ultimately the target to load the model into + * @return A {@link GenericRequest} to set options for the load and ultimately the target to load the model into */ - public static StreamRequest load(Uri uri) { - return new StreamRequest(uri); + public static Request load(Uri uri) { + return new Request(uri); } /** @@ -442,28 +318,26 @@ public class Glide { * given {@link URL}. Defaults to {@link VolleyUrlLoader.Factory} and {@link VolleyUrlLoader} to load the given * model. * - * @see #using(ModelLoaderFactory) - * @see ModelRequest#load(java.net.URL) + * @see #using(StreamModelLoader) * * @param url The URL representing the image. - * @return A {@link Request} to set options for the load and ultimately the target to load the model into + * @return A {@link GenericRequest} to set options for the load and ultimately the target to load the model into */ - public static StreamRequest load(URL url) { - return new StreamRequest(url); + public static Request load(URL url) { + return new Request(url); } /** * Use the {@link ModelLoaderFactory} currently registered for {@link File} to load the image represented by the * given {@link File}. Defaults to {@link StreamFileLoader.Factory} and {@link StreamFileLoader} to load the given model. * - * @see #using(ModelLoaderFactory) - * @see ModelRequest#load(java.io.File) + * @see #using(StreamModelLoader) * * @param file The File containing the image - * @return A {@link Request} to set options for the load and ultimately the target to load the model into + * @return A {@link GenericRequest} to set options for the load and ultimately the target to load the model into */ - public static StreamRequest load(File file) { - return new StreamRequest(file); + public static Request load(File file) { + return new Request(file); } /** @@ -471,27 +345,41 @@ public class Glide { * given {@link Integer} resource id. Defaults to {@link StreamResourceLoader.Factory} and {@link StreamResourceLoader} to load * the given model. * - * @see #using(ModelLoaderFactory) - * @see ModelRequest#load(Integer) + * @see #using(StreamModelLoader) * * @param resourceId the id of the resource containing the image - * @return A {@link Request} to set options for the load and ultimately the target to load the model into + * @return A {@link GenericRequest} to set options for the load and ultimately the target to load the model into */ - public static StreamRequest load(Integer resourceId) { - return new StreamRequest(resourceId); + public static Request load(Integer resourceId) { + return new Request(resourceId); } /** * Use the {@link ModelLoaderFactory} currently registered for the given model type to load the image represented by * the given model. * - * @param model The model to load - * @param The type of the model to load - * @return A {@link Request} to set options for the load and ultimately the target to load the model into - * @throws IllegalArgumentException If no {@link ModelLoaderFactory} is registered for the given model type + * @param model The model to load. + * @param The type of the model to load. + * @return A {@link GenericRequest} to set options for the load and ultimately the target to load the image into. + * @throws IllegalArgumentException If no such {@link ModelLoaderFactory} is registered for the given model type. + */ + @SuppressWarnings("unused") + public static Request loadFromImage(T model) { + return new ImageModelRequest(GLIDE.getFactory(model, InputStream.class)).load(model); + } + + /** + * Use the {@link ModelLoaderFactory} currently registered for the given model type for + * {@link ParcelFileDescriptor}s to load a thumbnail for the video represented by the given model. + * + * @param model The model to load. + * @param The type of the model to load. + * @return A {@link Request} to set options for the load an ultimately the target to load the thumbnail into. + * @throws IllegalArgumentException If no such {@link ModelLoaderFactory} is registered for the given model type. */ - public static StreamRequest load(T model) { - return new StreamRequest(model); + @SuppressWarnings("unused") + public static Request loadFromVideo(T model) { + return new VideoModelRequest(GLIDE.getFactory(model, ParcelFileDescriptor.class)).loadFromVideo(model); } /** @@ -519,70 +407,83 @@ public class Glide { return cancelled; } - public static class FileDescriptorModelRequest { + /** + * A helper class for building requests with custom {@link ModelLoader}s that translate models to + * {@link ParcelFileDescriptor} resources for loading video thumbnails. + * + * @param The type of the model. + */ + public static class VideoModelRequest { private ModelLoaderFactory factory; - private FileDescriptorModelRequest(ModelLoaderFactory factory) { + private VideoModelRequest(ModelLoaderFactory factory) { this.factory = factory; } - public Request load(T model) { - return new Request(model, factory).decoder(new VideoBitmapDecoder()); + public Request loadFromVideo(T model) { + return new Request(model, null, factory); } } /** * A helper class for building requests with custom {@link ModelLoader}s that translate models to - * {@link InputStream} resources. + * {@link InputStream} resources for loading images. * * @param The type of the model. */ - public static class StreamModelRequest { + public static class ImageModelRequest { private final ModelLoaderFactory factory; - private StreamModelRequest(ModelLoaderFactory factory) { + private ImageModelRequest(ModelLoaderFactory factory) { this.factory = factory; } - public StreamRequest load(T model) { - return new StreamRequest(model, factory); + public Request load(T model) { + return new Request(model, factory, null); } } /** - * A helper class for building requests with custom {@link ModelLoader}s - * - * @param The type of the model (and {@link ModelLoader} + * An request for the user to provide an {@link Context} to start an image load. */ - public static class ModelRequest { - private final ModelLoaderFactory factory; + public static class ContextRequest { + private final GenericRequest request; + private final Target target; - private ModelRequest(ModelLoaderFactory factory) { - this.factory = factory; + private ContextRequest(GenericRequest request, Target target) { + this.request = request; + this.target = target; } - public Request load(T model) { - return new Request(model, factory); + /** + * Start loading the image using the given context. The context will not be referenced statically so any + * context is acceptable. + * + * @param context The context to use to help load the image. + */ + public void with(Context context) { + request.finish(context, target); } } - /** - * Sets a variety of type independent options including resizing, animations, and placeholders. Responsible - * for building or retrieving an ImagePresenter for the given target and passing the ImagePresenter the given model. - * - * @see Request + /** + * A class for creating a request to load a bitmap for an image or from a video. Sets a variety of type independent + * options including resizing, animations, and placeholders. * - * @param The type of model that will be loaded into the target + * @param The type of model that will be loaded into the target. */ - public static class StreamRequest extends Request { - private StreamRequest(T model) { - super(model, InputStream.class); - approximate(); + @SuppressWarnings("unused") //public api + public static class Request extends GenericRequest { + private Request(ModelType model) { + this(model, GLIDE.getFactory(model, InputStream.class), + GLIDE.getFactory(model, ParcelFileDescriptor.class)); } - private StreamRequest(T model, ModelLoaderFactory factory) { - super(model, factory); - approximate(); + private Request(ModelType model, + ModelLoaderFactory imageFactory, + ModelLoaderFactory videoFactory) { + super(model, imageFactory, videoFactory); + approximate().videoDecoder(new VideoBitmapDecoder()); } /** @@ -592,7 +493,7 @@ public class Glide { * * @return This Request */ - public StreamRequest approximate() { + public Request approximate() { return downsample(Downsampler.AT_LEAST); } @@ -603,128 +504,161 @@ public class Glide { * * @return This Request */ - public StreamRequest asIs() { + public Request asIs() { return downsample(Downsampler.NONE); } /** - * Load images using the given {@link Downsampler}. Replaces any existing downsampler. Defaults to - * {@link Downsampler#AT_LEAST} + * Load images using the given {@link Downsampler}. Replaces any existing image decoder. Defaults to + * {@link Downsampler#AT_LEAST}. Will be ignored if the data represented by the model is a video. + * + * @see #imageDecoder + * @see #videoDecoder(BitmapDecoder) * * @param downsampler The downsampler * @return This Request */ - public StreamRequest downsample(Downsampler downsampler) { - super.decoder(downsampler); + public Request downsample(Downsampler downsampler) { + super.imageDecoder(downsampler); + return this; + } + + @Override + public Request imageDecoder(BitmapDecoder decoder) { + super.imageDecoder(decoder); return this; } @Override - public StreamRequest decoder(BitmapDecoder decoder) { - super.decoder(decoder); + public Request videoDecoder(BitmapDecoder decoder) { + super.videoDecoder(decoder); return this; } @Override - public StreamRequest centerCrop() { + public Request centerCrop() { super.centerCrop(); return this; } @Override - public StreamRequest fitCenter() { + public Request fitCenter() { super.fitCenter(); return this; } @Override - public StreamRequest transform(Transformation transformation) { + public Request transform(Transformation transformation) { super.transform(transformation); return this; } @Override - public StreamRequest transform(TransformationLoader transformationLoader) { + public Request transform( + TransformationLoader transformationLoader) { super.transform(transformationLoader); return this; } @Override - public StreamRequest animate(int animationId) { + public Request animate(int animationId) { super.animate(animationId); return this; } @Override - public StreamRequest placeholder(int resourceId) { + public Request placeholder(int resourceId) { super.placeholder(resourceId); return this; } @Override - public StreamRequest error(int resourceId) { + public Request error(int resourceId) { super.error(resourceId); return this; } @Override - public StreamRequest listener(RequestListener requestListener) { + public Request listener(RequestListener requestListener) { super.listener(requestListener); return this; } } /** - * Sets a variety of type independent options including resizing, animations, and placeholders. Responsible - * for building or retrieving an ImagePresenter for the given target and passing the ImagePresenter the given model. - * - * @param The type of model that will be loaded into the target. - * @param The type of the resource the model loader for this request will translate the model to and the decoder - * for this request can decode an {@link Bitmap} from. + * A generic class that can handle loading a bitmap either from an image or as a thumbnail from a video given + * models loaders to translate a model into generic resources for either an image or a video and decoders that can + * decode those resources into bitmaps. + * + * @param The type of model representing the image or video. + * @param The resource type that the image {@link ModelLoader} will provide that can be decoded + * by the image {@link BitmapDecoder}. + * @param The resource type that the video {@link ModelLoader} will provide that can be decoded + * by the video {@link BitmapDecoder}. */ - @SuppressWarnings("unused") //public api - public static class Request { - + private static class GenericRequest { private Context context; - private Target target; - - private ModelLoaderFactory modelLoaderFactory; - private final T model; + private ModelLoaderFactory imageModelLoaderFactory; + private final ModelLoaderFactory videoModelLoaderFactory; + private final ModelType model; private int animationId = -1; private int placeholderId = -1; private int errorId = -1; - private ArrayList> transformationLoaders = new ArrayList>(); - private RequestListener requestListener; - private BitmapDecoder decoder; + private ArrayList> transformationLoaders = new ArrayList>(); + private RequestListener requestListener; + private BitmapDecoder imageDecoder; + private BitmapDecoder videoDecoder; - private Request(T model, Class decoderClazz) { - this(model, GLIDE.getFactory(model, decoderClazz)); - } - - private Request(T model, ModelLoaderFactory factory) { + private GenericRequest(ModelType model, ModelLoaderFactory imageFactory, + ModelLoaderFactory videoFactory) { if (model == null ) { throw new IllegalArgumentException("Model can't be null"); } this.model = model; - if (factory == null) { - throw new IllegalArgumentException("No ModelLoaderFactory registered for class=" + model.getClass()); + if (imageFactory == null && videoFactory == null) { + throw new IllegalArgumentException("No ModelLoaderFactorys registered for either image or video type," + + " class=" + model.getClass()); } - this.modelLoaderFactory = factory; + this.imageModelLoaderFactory = imageFactory; + this.videoModelLoaderFactory = videoFactory; } /** - * Loads the image from the given resource type into an {@link Bitmap} using the given - * {@link BitmapDecoder}. + * Loads the image from the given resource type into an {@link Bitmap} using the given {@link BitmapDecoder}. + * + *

+ * Will be ignored if the data represented by the given model is not an image. + *

* * @see Downsampler * - * @param decoder The {@link BitmapDecoder} to use to decode the resource. + * @param decoder The {@link BitmapDecoder} to use to decode the image resource. * @return This Request. */ - public Request decoder(BitmapDecoder decoder) { - this.decoder = decoder; + public GenericRequest imageDecoder( + BitmapDecoder decoder) { + this.imageDecoder = decoder; + + return this; + } + + /** + * Loads the video from the given resource type into an {@link Bitmap} using the given {@link BitmapDecoder}. + * + *

+ * Will be ignored if the data represented by the given model is not a video. + *

+ * + * @see VideoBitmapDecoder + * + * @param decoder The {@link BitmapDecoder} to use to decode the video resource. + * @return This request. + */ + public GenericRequest videoDecoder( + BitmapDecoder decoder) { + this.videoDecoder = decoder; return this; } @@ -736,8 +670,8 @@ public class Glide { * * @return This Request */ - public Request centerCrop() { - return transform(new CenterCrop()); + public GenericRequest centerCrop() { + return transform(new CenterCrop()); } /** @@ -747,8 +681,8 @@ public class Glide { * * @return This Request */ - public Request fitCenter() { - return transform(new FitCenter()); + public GenericRequest fitCenter() { + return transform(new FitCenter()); } /** @@ -759,10 +693,11 @@ public class Glide { * @param transformation The transformation to use * @return This Request */ - public Request transform(final Transformation transformation) { - return transform(new TransformationLoader() { + public GenericRequest transform( + final Transformation transformation) { + return transform(new TransformationLoader() { @Override - public Transformation getTransformation(T model) { + public Transformation getTransformation(ModelType model) { return transformation; } @@ -780,7 +715,8 @@ public class Glide { * @param transformationLoader The loader to obtaian a transformation for a given model * @return This Request */ - public Request transform(TransformationLoader transformationLoader) { + public GenericRequest transform( + TransformationLoader transformationLoader) { transformationLoaders.add(transformationLoader); return this; @@ -793,7 +729,7 @@ public class Glide { * @param animationId The resource id of the animation to run * @return This Request */ - public Request animate(int animationId) { + public GenericRequest animate(int animationId) { this.animationId = animationId; return this; @@ -805,7 +741,7 @@ public class Glide { * @param resourceId The id of the resource to use as a placeholder * @return This Request */ - public Request placeholder(int resourceId) { + public GenericRequest placeholder(int resourceId) { this.placeholderId = resourceId; return this; @@ -817,7 +753,7 @@ public class Glide { * @param resourceId The id of the resource to use as a placeholder * @return This request */ - public Request error(int resourceId) { + public GenericRequest error(int resourceId) { this.errorId = resourceId; return this; @@ -831,7 +767,8 @@ public class Glide { * @param requestListener The request listener to use * @return This request */ - public Request listener(RequestListener requestListener) { + public GenericRequest listener( + RequestListener requestListener) { this.requestListener = requestListener; return this; @@ -869,9 +806,8 @@ public class Glide { private void finish(Context context, Target target) { this.context = context; - this.target = target; - ImagePresenter imagePresenter = getImagePresenter(target); + ImagePresenter imagePresenter = getImagePresenter(target); imagePresenter.setModel(model); } @@ -880,8 +816,8 @@ public class Glide { * the target's ImagePresenter via {@link Target#setImagePresenter(com.bumptech.glide.presenter.ImagePresenter)} */ @SuppressWarnings("unchecked") - private ImagePresenter getImagePresenter(Target target) { - ImagePresenter result = target.getImagePresenter(); + private ImagePresenter getImagePresenter(Target target) { + ImagePresenter result = target.getImagePresenter(); Metadata previous = GLIDE.metadataTracker.get(target); Metadata current = new Metadata(this); @@ -904,13 +840,22 @@ public class Glide { return result; } - private ImagePresenter buildImagePresenter(final Target target) { - TransformationLoader transformationLoader = getFinalTransformationLoader(); - final ModelLoader modelLoader = modelLoaderFactory.build(context, GLIDE.loaderFactory); + private ImagePresenter buildImagePresenter(final Target target) { + TransformationLoader transformationLoader = getFinalTransformationLoader(); + + ModelLoader imageModelLoader = null; + if (imageModelLoaderFactory != null) { + imageModelLoader = imageModelLoaderFactory.build(context, GLIDE.loaderFactory); + } + ModelLoader videoModelLoader = null; + if (videoModelLoaderFactory != null) { + videoModelLoader = videoModelLoaderFactory.build(context, GLIDE.loaderFactory); + } - ImagePresenter.Builder builder = new ImagePresenter.Builder() + ImagePresenter.Builder builder = new ImagePresenter.Builder() .setTarget(target, context) - .setBitmapLoadFactory(new BaseBitmapLoadFactory(modelLoader, decoder, transformationLoader)) + .setBitmapLoadFactory(new BaseBitmapLoadFactory( + imageModelLoader, imageDecoder, videoModelLoader, videoDecoder, transformationLoader)) .setImageLoader(new ImageManagerLoader(context)); if (animationId != -1 || requestListener != null) { @@ -920,9 +865,9 @@ public class Glide { } else { animation = null; } - builder.setImageReadyCallback(new ImagePresenter.ImageReadyCallback() { + builder.setImageReadyCallback(new ImagePresenter.ImageReadyCallback() { @Override - public void onImageReady(T model, Target target, boolean fromCache) { + public void onImageReady(ModelType model, Target target, boolean fromCache) { if (animation != null && !fromCache) { target.startAnimation(animation); } @@ -942,9 +887,9 @@ public class Glide { } if (requestListener != null) { - builder.setExceptionHandler(new ImagePresenter.ExceptionHandler() { + builder.setExceptionHandler(new ImagePresenter.ExceptionHandler() { @Override - public void onException(Exception e, T model, boolean isCurrent) { + public void onException(Exception e, ModelType model, boolean isCurrent) { if (isCurrent) { requestListener.onException(e, model, target); } @@ -955,14 +900,14 @@ public class Glide { return builder.build(); } - private TransformationLoader getFinalTransformationLoader() { + private TransformationLoader getFinalTransformationLoader() { switch (transformationLoaders.size()) { case 0: - return new None(); + return new None(); case 1: return transformationLoaders.get(0); default: - return new MultiTransformationLoader(transformationLoaders); + return new MultiTransformationLoader(transformationLoaders); } } @@ -982,27 +927,23 @@ public class Glide { } } - /** - * An request for the user to provide an {@link Context} to start an image load - */ - public static class ContextRequest { - private final Request request; - private final Target target; - private ContextRequest(Request request, Target target) { - this.request = request; - this.target = target; - } + private static ModelLoaderFactory modelLoaderToFactory(final ModelLoader modelLoader) { + return new ModelLoaderFactory() { + @Override + public ModelLoader build(Context context, GenericLoaderFactory factories) { + return modelLoader; + } - /** - * Start loading the image using the given context. The context will not be referenced statically so any - * context is acceptable. - * - * @param context The context to use to help load the image - */ - public void with(Context context) { - request.finish(context, target); - } + @SuppressWarnings("unchecked") + @Override + public Class> loaderClass() { + return (Class>) modelLoader.getClass(); + } + + @Override + public void teardown() { } + }; } private static class Metadata { @@ -1016,10 +957,12 @@ public class Glide { private final Class requestListenerClass; private final String decoderId; - public Metadata(Request request) { + public Metadata(GenericRequest request) { modelClass = request.model.getClass(); - modelLoaderClass = request.modelLoaderFactory.loaderClass(); - decoderId = request.decoder.getId(); + modelLoaderClass = request.imageModelLoaderFactory + .loaderClass(); + decoderId = request.imageDecoder + .getId(); transformationId = request.getFinalTransformationId(); animationId = request.animationId; placeholderId = request.placeholderId; diff --git a/library/src/com/bumptech/glide/loader/bitmap/BaseBitmapLoadFactory.java b/library/src/com/bumptech/glide/loader/bitmap/BaseBitmapLoadFactory.java index 680b86a64..f3f1f03eb 100644 --- a/library/src/com/bumptech/glide/loader/bitmap/BaseBitmapLoadFactory.java +++ b/library/src/com/bumptech/glide/loader/bitmap/BaseBitmapLoadFactory.java @@ -11,32 +11,54 @@ import com.bumptech.glide.resize.load.Transformation; /** * A base {@link BitmapLoadFactory} that composes {@link ModelLoader} and {@link BitmapDecoder} sub-components - * to create an {@link BitmapLoadTask}. + * to create an {@link BitmapLoadTask} capable of loading a model that represents either an image or a video. * * @param The type of the model. - * @param The type of the resource that the {@link ModelLoader} provides and the {@link BitmapDecoder} can + * @param The type of the resource that the image {@link ModelLoader} provides and the image {@link BitmapDecoder} can * decode.` + * @param The type of resource that the video {@link ModelLoader} provides and the video {@link BitmapDecoder} can + * decode. */ -public class BaseBitmapLoadFactory implements BitmapLoadFactory { - private final ModelLoader modelLoader; - private final BitmapDecoder decoder; +public class BaseBitmapLoadFactory implements BitmapLoadFactory { + private final ModelLoader imageModelLoader; + private final BitmapDecoder imageDecoder; + private final ModelLoader videoModelLoader; + private final BitmapDecoder videoDecoder; private final TransformationLoader transformationLoader; - public BaseBitmapLoadFactory(ModelLoader modelLoader, BitmapDecoder decoder) { - this(modelLoader, decoder, new None()); + @SuppressWarnings("unused") + public BaseBitmapLoadFactory(ModelLoader imageModelLoader, BitmapDecoder imageDecoder) { + this(imageModelLoader, imageDecoder, null, null, new None()); } - public BaseBitmapLoadFactory(ModelLoader modelLoader, BitmapDecoder decoder, + @SuppressWarnings("unused") + public BaseBitmapLoadFactory(ModelLoader imageModelLoader, BitmapDecoder imageDecoder, TransformationLoader transformationLoader) { - this.modelLoader = modelLoader; - this.decoder = decoder; + this(imageModelLoader, imageDecoder, null, null, transformationLoader); + } + + public BaseBitmapLoadFactory(ModelLoader imageModelLoader, BitmapDecoder imageDecoder, + ModelLoader videoModelLoader, BitmapDecoder videoDecoder, + TransformationLoader transformationLoader) { + this.imageModelLoader = imageModelLoader; + this.imageDecoder = imageDecoder; + this.videoModelLoader = videoModelLoader; + this.videoDecoder = videoDecoder; this.transformationLoader = transformationLoader; } @Override public BitmapLoadTask getLoadTask(T model, int width, int height) { - ResourceFetcher resourceFetcher = modelLoader.getResourceFetcher(model, width, height); + ResourceFetcher imageFetcher = null; + if (imageModelLoader != null) { + imageFetcher = imageModelLoader.getResourceFetcher(model, width, height); + } + ResourceFetcher videoFetcher = null; + if (videoModelLoader != null) { + videoFetcher = videoModelLoader.getResourceFetcher(model, width, height); + } Transformation transformation = transformationLoader.getTransformation(model); - return new BaseBitmapLoadTask(resourceFetcher, decoder, transformation, width, height); + return new BaseBitmapLoadTask(imageFetcher, imageDecoder, videoFetcher, videoDecoder, transformation, + width, height); } } diff --git a/library/src/com/bumptech/glide/loader/bitmap/model/GenericLoaderFactory.java b/library/src/com/bumptech/glide/loader/bitmap/model/GenericLoaderFactory.java index 3e7d0f0f3..038c9f6f4 100644 --- a/library/src/com/bumptech/glide/loader/bitmap/model/GenericLoaderFactory.java +++ b/library/src/com/bumptech/glide/loader/bitmap/model/GenericLoaderFactory.java @@ -39,10 +39,7 @@ public class GenericLoaderFactory { public ModelLoader buildModelLoader(Class modelClass, Class resourceClass, Context context) { final ModelLoaderFactory factory = getFactory(modelClass, resourceClass); - if (factory == null) { - throw new IllegalArgumentException("No ModelLoaderFactory registered for class=" + modelClass); - } - return factory.build(context, this); + return factory != null ? factory.build(context, this) : null; } @SuppressWarnings("unchecked") diff --git a/library/src/com/bumptech/glide/loader/bitmap/model/UriLoader.java b/library/src/com/bumptech/glide/loader/bitmap/model/UriLoader.java index dfa57ed7b..faef7df3b 100644 --- a/library/src/com/bumptech/glide/loader/bitmap/model/UriLoader.java +++ b/library/src/com/bumptech/glide/loader/bitmap/model/UriLoader.java @@ -24,7 +24,7 @@ public abstract class UriLoader implements ModelLoader{ ResourceFetcher result = null; if (isLocalUri(scheme)) { result = getLocalUriFetcher(context, model); - } else if ("http".equals(scheme) || "https".equals(scheme)) { + } else if (urlLoader != null && ("http".equals(scheme) || "https".equals(scheme))) { try { result = urlLoader.getResourceFetcher(new URL(model.toString()), width, height); } catch (MalformedURLException e) { @@ -32,10 +32,6 @@ public abstract class UriLoader implements ModelLoader{ } } - if (result == null) { - throw new IllegalArgumentException("No stream loader for uri=" + model); - } - return result; } diff --git a/library/src/com/bumptech/glide/resize/BaseBitmapLoadTask.java b/library/src/com/bumptech/glide/resize/BaseBitmapLoadTask.java index 524a20969..0c88f3a01 100644 --- a/library/src/com/bumptech/glide/resize/BaseBitmapLoadTask.java +++ b/library/src/com/bumptech/glide/resize/BaseBitmapLoadTask.java @@ -8,40 +8,47 @@ import com.bumptech.glide.resize.load.Transformation; /** * A base {@link BitmapLoadTask} that composes {@link ResourceFetcher} and {@link BitmapDecoder} to decode a - * bitmap. + * bitmap from either an image or a video. * - * @param The type of the resource returned by the {@link ResourceFetcher} and used by the - * {@link BitmapDecoder} to BitmapResourceLoader the bitmap. + * @param The type of the resource returned by the image {@link ResourceFetcher} and used by the + * image {@link BitmapDecoder} to decode the bitmap. + * @param The type of the resource returned by the video {@link ResourceFetcher} and used by the + * video {@link BitmapDecoder} to decode the bitmap. */ -public class BaseBitmapLoadTask implements BitmapLoadTask { +public class BaseBitmapLoadTask implements BitmapLoadTask { private final String id; private final int width; private final int height; + private final ResourceFetcher videoLoader; + private final BitmapDecoder videoDecoder; private final Transformation transformation; - private ResourceFetcher loader; - private BitmapDecoder decoder; + private ResourceFetcher imageLoader; + private BitmapDecoder imageDecoder; - public BaseBitmapLoadTask(ResourceFetcher loader, BitmapDecoder decoder, Transformation transformation, + public BaseBitmapLoadTask(ResourceFetcher imageLoader, BitmapDecoder imageDecoder, + ResourceFetcher videoLoader, BitmapDecoder videoDecoder, Transformation transformation, int width, int height) { - this.loader = loader; - this.decoder = decoder; + this.imageLoader = imageLoader; + this.imageDecoder = imageDecoder; + this.videoLoader = videoLoader; + this.videoDecoder = videoDecoder; this.transformation = transformation; this.width = width; this.height = height; - this.id = loader.getId() + decoder.getId() + transformation.getId() + width + height; + this.id = imageLoader.getId() + imageDecoder.getId() + transformation.getId() + width + height; } public void cancel() { - loader.cancel(); + imageLoader.cancel(); } @Override public Bitmap load(BitmapPool bitmapPool) throws Exception { - T resource = loader.loadResource(); - if (resource == null) { - throw new IllegalStateException("Cannot decode null resource"); + Bitmap original = loadOriginal(bitmapPool); + if (original == null) { + return null; } - Bitmap original = decoder.decode(resource, bitmapPool, width, height); + Bitmap transformed = transformation.transform(original, bitmapPool, width, height); if (original != transformed) { bitmapPool.put(original); @@ -49,6 +56,30 @@ public class BaseBitmapLoadTask implements BitmapLoadTask { return transformed; } + private Bitmap loadOriginal(BitmapPool bitmapPool) throws Exception { + Bitmap result = loadOriginal(imageLoader, imageDecoder, bitmapPool); + if (result == null) { + result = loadOriginal(videoLoader, videoDecoder, bitmapPool); + } + + return result; + } + + private Bitmap loadOriginal(ResourceFetcher fetcher, BitmapDecoder decoder, BitmapPool bitmapPool) + throws Exception { + if (fetcher == null || decoder == null) { + return null; + } + + X resource = fetcher.loadResource(); + if (resource == null) { + return null; + } + + return decoder.decode(resource, bitmapPool, width, height); + + } + public String getId() { return id; } diff --git a/library/tests/src/com/bumptech/glide/GlideTest.java b/library/tests/src/com/bumptech/glide/GlideTest.java index 0984fb8e3..1f9935dc6 100644 --- a/library/tests/src/com/bumptech/glide/GlideTest.java +++ b/library/tests/src/com/bumptech/glide/GlideTest.java @@ -5,7 +5,6 @@ import android.net.Uri; import android.test.ActivityTestCase; import android.view.ViewGroup; import android.widget.ImageView; -import com.bumptech.glide.loader.bitmap.model.ModelLoader; import com.bumptech.glide.loader.bitmap.model.stream.StreamModelLoader; import com.bumptech.glide.loader.bitmap.resource.ResourceFetcher; import com.bumptech.glide.presenter.ImagePresenter; diff --git a/library/tests/src/com/bumptech/glide/ListPreloaderTest.java b/library/tests/src/com/bumptech/glide/ListPreloaderTest.java index a3b20f815..ec1d1e0a2 100644 --- a/library/tests/src/com/bumptech/glide/ListPreloaderTest.java +++ b/library/tests/src/com/bumptech/glide/ListPreloaderTest.java @@ -3,7 +3,6 @@ package com.bumptech.glide; import android.content.Context; import android.graphics.Bitmap; import android.test.AndroidTestCase; -import com.bumptech.glide.loader.bitmap.model.ModelLoader; import com.bumptech.glide.loader.bitmap.model.stream.StreamModelLoader; import com.bumptech.glide.loader.bitmap.resource.ResourceFetcher; diff --git a/samples/flickr/src/com/bumptech/glide/samples/flickr/FlickrModelLoader.java b/samples/flickr/src/com/bumptech/glide/samples/flickr/FlickrModelLoader.java index 882cfeacb..b70a9e08a 100644 --- a/samples/flickr/src/com/bumptech/glide/samples/flickr/FlickrModelLoader.java +++ b/samples/flickr/src/com/bumptech/glide/samples/flickr/FlickrModelLoader.java @@ -1,8 +1,8 @@ package com.bumptech.glide.samples.flickr; import android.content.Context; -import com.bumptech.glide.loader.bitmap.model.BaseUrlLoader; import com.bumptech.glide.loader.bitmap.model.Cache; +import com.bumptech.glide.loader.bitmap.model.stream.BaseUrlLoader; import com.bumptech.glide.samples.flickr.api.Api; import com.bumptech.glide.samples.flickr.api.Photo; diff --git a/samples/flickr/src/com/bumptech/glide/samples/flickr/FlickrPhotoGrid.java b/samples/flickr/src/com/bumptech/glide/samples/flickr/FlickrPhotoGrid.java index 261d61add..ad0aea75e 100644 --- a/samples/flickr/src/com/bumptech/glide/samples/flickr/FlickrPhotoGrid.java +++ b/samples/flickr/src/com/bumptech/glide/samples/flickr/FlickrPhotoGrid.java @@ -139,7 +139,7 @@ public class FlickrPhotoGrid extends SherlockFragment implements PhotoViewer { //reason why ImagePresenter is used here and not in FlickrPhotoList. final Animation fadeIn = AnimationUtils.loadAnimation(context, R.anim.fade_in); imagePresenter = new ImagePresenter.Builder() - .setBitmapLoadFactory(new BaseBitmapLoadFactory( + .setBitmapLoadFactory(new BaseBitmapLoadFactory( new FlickrModelLoader(context, urlCache), Downsampler.AT_LEAST, new CenterCrop())) .setImageView(imageView) diff --git a/samples/flickr/src/com/bumptech/glide/samples/flickr/FlickrSearchActivity.java b/samples/flickr/src/com/bumptech/glide/samples/flickr/FlickrSearchActivity.java index 9cb9fdb73..ed682e6c5 100644 --- a/samples/flickr/src/com/bumptech/glide/samples/flickr/FlickrSearchActivity.java +++ b/samples/flickr/src/com/bumptech/glide/samples/flickr/FlickrSearchActivity.java @@ -31,6 +31,7 @@ import com.bumptech.glide.volley.VolleyUrlLoader; import java.io.File; import java.io.IOException; +import java.io.InputStream; import java.net.URL; import java.util.ArrayList; import java.util.HashMap; @@ -112,8 +113,7 @@ public class FlickrSearchActivity extends SherlockFragmentActivity { } requestQueue = Volley.newRequestQueue(this); - - glide.register(URL.class, new VolleyUrlLoader.Factory(requestQueue)); + glide.register(URL.class, InputStream.class, new VolleyUrlLoader.Factory(requestQueue)); searching = findViewById(R.id.searching); searchLoading = findViewById(R.id.search_loading); -- GitLab