Home | History | Annotate | Download | only in glide
      1 package com.bumptech.glide;
      2 
      3 import android.annotation.TargetApi;
      4 import android.app.Activity;
      5 import android.content.Context;
      6 import android.graphics.Bitmap;
      7 import android.graphics.drawable.Drawable;
      8 import android.net.Uri;
      9 import android.os.Build;
     10 import android.os.Handler;
     11 import android.os.Looper;
     12 import android.os.ParcelFileDescriptor;
     13 import android.support.v4.app.Fragment;
     14 import android.support.v4.app.FragmentActivity;
     15 import android.util.Log;
     16 import android.view.View;
     17 import android.widget.ImageView;
     18 
     19 import com.bumptech.glide.load.DecodeFormat;
     20 import com.bumptech.glide.load.engine.Engine;
     21 import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool;
     22 import com.bumptech.glide.load.engine.cache.MemoryCache;
     23 import com.bumptech.glide.load.engine.prefill.BitmapPreFiller;
     24 import com.bumptech.glide.load.engine.prefill.PreFillType;
     25 import com.bumptech.glide.load.model.GenericLoaderFactory;
     26 import com.bumptech.glide.load.model.GlideUrl;
     27 import com.bumptech.glide.load.model.ImageVideoWrapper;
     28 import com.bumptech.glide.load.model.ModelLoader;
     29 import com.bumptech.glide.load.model.ModelLoaderFactory;
     30 import com.bumptech.glide.load.model.file_descriptor.FileDescriptorFileLoader;
     31 import com.bumptech.glide.load.model.file_descriptor.FileDescriptorResourceLoader;
     32 import com.bumptech.glide.load.model.file_descriptor.FileDescriptorStringLoader;
     33 import com.bumptech.glide.load.model.file_descriptor.FileDescriptorUriLoader;
     34 import com.bumptech.glide.load.model.stream.HttpUrlGlideUrlLoader;
     35 import com.bumptech.glide.load.model.stream.StreamByteArrayLoader;
     36 import com.bumptech.glide.load.model.stream.StreamFileLoader;
     37 import com.bumptech.glide.load.model.stream.StreamResourceLoader;
     38 import com.bumptech.glide.load.model.stream.StreamStringLoader;
     39 import com.bumptech.glide.load.model.stream.StreamUriLoader;
     40 import com.bumptech.glide.load.model.stream.StreamUrlLoader;
     41 import com.bumptech.glide.load.resource.bitmap.CenterCrop;
     42 import com.bumptech.glide.load.resource.bitmap.FileDescriptorBitmapDataLoadProvider;
     43 import com.bumptech.glide.load.resource.bitmap.FitCenter;
     44 import com.bumptech.glide.load.resource.bitmap.GlideBitmapDrawable;
     45 import com.bumptech.glide.load.resource.bitmap.ImageVideoDataLoadProvider;
     46 import com.bumptech.glide.load.resource.bitmap.StreamBitmapDataLoadProvider;
     47 import com.bumptech.glide.load.resource.drawable.GlideDrawable;
     48 import com.bumptech.glide.load.resource.file.StreamFileDataLoadProvider;
     49 import com.bumptech.glide.load.resource.gif.GifDrawable;
     50 import com.bumptech.glide.load.resource.gif.GifDrawableLoadProvider;
     51 import com.bumptech.glide.load.resource.gifbitmap.GifBitmapWrapper;
     52 import com.bumptech.glide.load.resource.gifbitmap.GifBitmapWrapperTransformation;
     53 import com.bumptech.glide.load.resource.gifbitmap.ImageVideoGifDrawableLoadProvider;
     54 import com.bumptech.glide.load.resource.transcode.GifBitmapWrapperDrawableTranscoder;
     55 import com.bumptech.glide.load.resource.transcode.GlideBitmapDrawableTranscoder;
     56 import com.bumptech.glide.load.resource.transcode.ResourceTranscoder;
     57 import com.bumptech.glide.load.resource.transcode.TranscoderRegistry;
     58 import com.bumptech.glide.manager.RequestManagerRetriever;
     59 import com.bumptech.glide.provider.DataLoadProvider;
     60 import com.bumptech.glide.provider.DataLoadProviderRegistry;
     61 import com.bumptech.glide.request.FutureTarget;
     62 import com.bumptech.glide.request.Request;
     63 import com.bumptech.glide.request.animation.GlideAnimation;
     64 import com.bumptech.glide.request.target.ImageViewTargetFactory;
     65 import com.bumptech.glide.request.target.Target;
     66 import com.bumptech.glide.request.target.ViewTarget;
     67 import com.bumptech.glide.util.Util;
     68 
     69 import java.io.File;
     70 import java.io.InputStream;
     71 import java.net.URL;
     72 
     73 /**
     74  * A singleton to present a simple static interface for building requests with {@link BitmapRequestBuilder} and
     75  * maintaining an {@link Engine}, {@link BitmapPool}, {@link com.bumptech.glide.load.engine.cache.DiskCache} and
     76  * {@link MemoryCache}.
     77  */
     78 public class Glide {
     79     /** 250 MB of cache. */
     80     static final int DEFAULT_DISK_CACHE_SIZE = 250 * 1024 * 1024;
     81 
     82     private static final String DEFAULT_DISK_CACHE_DIR = "image_manager_disk_cache";
     83     private static final String TAG = "Glide";
     84     private static volatile Glide glide;
     85 
     86     private final GenericLoaderFactory loaderFactory;
     87     private final Engine engine;
     88     private final BitmapPool bitmapPool;
     89     private final MemoryCache memoryCache;
     90     private final DecodeFormat decodeFormat;
     91     private final ImageViewTargetFactory imageViewTargetFactory = new ImageViewTargetFactory();
     92     private final TranscoderRegistry transcoderRegistry = new TranscoderRegistry();
     93     private final DataLoadProviderRegistry dataLoadProviderRegistry;
     94     private final CenterCrop bitmapCenterCrop;
     95     private final GifBitmapWrapperTransformation drawableCenterCrop;
     96     private final FitCenter bitmapFitCenter;
     97     private final GifBitmapWrapperTransformation drawableFitCenter;
     98     private final Handler mainHandler;
     99     private final BitmapPreFiller bitmapPreFiller;
    100 
    101     /**
    102      * Returns a directory with a default name in the private cache directory of the application to use to store
    103      * retrieved media and thumbnails.
    104      *
    105      * @see #getPhotoCacheDir(android.content.Context, String)
    106      *
    107      * @param context A context.
    108      */
    109     public static File getPhotoCacheDir(Context context) {
    110         return getPhotoCacheDir(context, DEFAULT_DISK_CACHE_DIR);
    111     }
    112 
    113     /**
    114      * Returns a directory with the given name in the private cache directory of the application to use to store
    115      * retrieved media and thumbnails.
    116      *
    117      * @see #getPhotoCacheDir(android.content.Context)
    118      *
    119      * @param context A context.
    120      * @param cacheName The name of the subdirectory in which to store the cache.
    121      */
    122     public static File getPhotoCacheDir(Context context, String cacheName) {
    123         File cacheDir = context.getCacheDir();
    124         if (cacheDir != null) {
    125             File result = new File(cacheDir, cacheName);
    126             if (!result.mkdirs() && (!result.exists() || !result.isDirectory())) {
    127                 // File wasn't able to create a directory, or the result exists but not a directory
    128                 return null;
    129             }
    130             return result;
    131         }
    132         if (Log.isLoggable(TAG, Log.ERROR)) {
    133             Log.e(TAG, "default disk cache dir is null");
    134         }
    135         return null;
    136     }
    137 
    138     /**
    139      * Get the singleton.
    140      *
    141      * @return the singleton
    142      */
    143     public static Glide get(Context context) {
    144         if (glide == null) {
    145             synchronized (Glide.class) {
    146                 if (glide == null) {
    147                     glide = new GlideBuilder(context).createGlide();
    148                 }
    149             }
    150         }
    151 
    152         return glide;
    153     }
    154 
    155     /**
    156      * Returns false if the {@link Glide} singleton has not yet been created and can therefore be setup using
    157      * {@link #setup(GlideBuilder)}.
    158      *
    159      * @see #setup(GlideBuilder)
    160      */
    161     public static boolean isSetup() {
    162         return glide != null;
    163     }
    164 
    165     /**
    166      * Creates the {@link Glide} singleton using the given builder. Can be used to set options like cache sizes and
    167      * locations.
    168      *
    169      * @see #isSetup()
    170      *
    171      * @param builder The builder.
    172      * @throws IllegalArgumentException if the Glide singleton has already been created.
    173      */
    174     public static void setup(GlideBuilder builder) {
    175         if (isSetup()) {
    176             throw new IllegalArgumentException("Glide is already setup, check with isSetup() first");
    177         }
    178 
    179         glide = builder.createGlide();
    180     }
    181 
    182     // For testing.
    183     static void tearDown() {
    184         glide = null;
    185     }
    186 
    187     Glide(Engine engine, MemoryCache memoryCache, BitmapPool bitmapPool, Context context, DecodeFormat decodeFormat) {
    188         this.engine = engine;
    189         this.bitmapPool = bitmapPool;
    190         this.memoryCache = memoryCache;
    191         this.decodeFormat = decodeFormat;
    192         loaderFactory = new GenericLoaderFactory(context);
    193         mainHandler = new Handler(Looper.getMainLooper());
    194         bitmapPreFiller = new BitmapPreFiller(memoryCache, bitmapPool, decodeFormat);
    195 
    196         dataLoadProviderRegistry = new DataLoadProviderRegistry();
    197 
    198         StreamBitmapDataLoadProvider streamBitmapLoadProvider =
    199                 new StreamBitmapDataLoadProvider(bitmapPool, decodeFormat);
    200         dataLoadProviderRegistry.register(InputStream.class, Bitmap.class, streamBitmapLoadProvider);
    201 
    202         FileDescriptorBitmapDataLoadProvider fileDescriptorLoadProvider =
    203                 new FileDescriptorBitmapDataLoadProvider(bitmapPool, decodeFormat);
    204         dataLoadProviderRegistry.register(ParcelFileDescriptor.class, Bitmap.class, fileDescriptorLoadProvider);
    205 
    206         ImageVideoDataLoadProvider imageVideoDataLoadProvider =
    207                 new ImageVideoDataLoadProvider(streamBitmapLoadProvider, fileDescriptorLoadProvider);
    208         dataLoadProviderRegistry.register(ImageVideoWrapper.class, Bitmap.class, imageVideoDataLoadProvider);
    209 
    210         GifDrawableLoadProvider gifDrawableLoadProvider =
    211                 new GifDrawableLoadProvider(context, bitmapPool);
    212         dataLoadProviderRegistry.register(InputStream.class, GifDrawable.class, gifDrawableLoadProvider);
    213 
    214         dataLoadProviderRegistry.register(ImageVideoWrapper.class, GifBitmapWrapper.class,
    215                 new ImageVideoGifDrawableLoadProvider(imageVideoDataLoadProvider, gifDrawableLoadProvider, bitmapPool));
    216 
    217         dataLoadProviderRegistry.register(InputStream.class, File.class, new StreamFileDataLoadProvider());
    218 
    219         register(File.class, ParcelFileDescriptor.class, new FileDescriptorFileLoader.Factory());
    220         register(File.class, InputStream.class, new StreamFileLoader.Factory());
    221         register(int.class, ParcelFileDescriptor.class, new FileDescriptorResourceLoader.Factory());
    222         register(int.class, InputStream.class, new StreamResourceLoader.Factory());
    223         register(Integer.class, ParcelFileDescriptor.class, new FileDescriptorResourceLoader.Factory());
    224         register(Integer.class, InputStream.class, new StreamResourceLoader.Factory());
    225         register(String.class, ParcelFileDescriptor.class, new FileDescriptorStringLoader.Factory());
    226         register(String.class, InputStream.class, new StreamStringLoader.Factory());
    227         register(Uri.class, ParcelFileDescriptor.class, new FileDescriptorUriLoader.Factory());
    228         register(Uri.class, InputStream.class, new StreamUriLoader.Factory());
    229         register(URL.class, InputStream.class, new StreamUrlLoader.Factory());
    230         register(GlideUrl.class, InputStream.class, new HttpUrlGlideUrlLoader.Factory());
    231         register(byte[].class, InputStream.class, new StreamByteArrayLoader.Factory());
    232 
    233         transcoderRegistry.register(Bitmap.class, GlideBitmapDrawable.class,
    234                 new GlideBitmapDrawableTranscoder(context.getResources(), bitmapPool));
    235         transcoderRegistry.register(GifBitmapWrapper.class, GlideDrawable.class,
    236                 new GifBitmapWrapperDrawableTranscoder(
    237                         new GlideBitmapDrawableTranscoder(context.getResources(), bitmapPool)));
    238 
    239         bitmapCenterCrop = new CenterCrop(bitmapPool);
    240         drawableCenterCrop = new GifBitmapWrapperTransformation(bitmapPool, bitmapCenterCrop);
    241 
    242         bitmapFitCenter = new FitCenter(bitmapPool);
    243         drawableFitCenter = new GifBitmapWrapperTransformation(bitmapPool, bitmapFitCenter);
    244     }
    245 
    246     /**
    247      * Returns the {@link com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool} used to temporarily store
    248      * {@link android.graphics.Bitmap}s so they can be reused to avoid garbage collections.
    249      *
    250      * <p>
    251      *     Note - Using this pool directly can lead to undefined behavior and strange drawing errors. Any
    252      *     {@link android.graphics.Bitmap} added to the pool must not be currently in use in any other part of the
    253      *     application. Any {@link android.graphics.Bitmap} added to the pool must be removed from the pool before it
    254      *     is added a second time.
    255      * </p>
    256      *
    257      * <p>
    258      *     Note - To make effective use of the pool, any {@link android.graphics.Bitmap} removed from the pool must
    259      *     eventually be re-added. Otherwise the pool will eventually empty and will not serve any useful purpose.
    260      * </p>
    261      *
    262      * <p>
    263      *     The primary reason this object is exposed is for use in custom
    264      *     {@link com.bumptech.glide.load.ResourceDecoder}s and {@link com.bumptech.glide.load.Transformation}s. Use
    265      *     outside of these classes is not generally recommended.
    266      * </p>
    267      */
    268     public BitmapPool getBitmapPool() {
    269         return bitmapPool;
    270     }
    271 
    272     <Z, R> ResourceTranscoder<Z, R> buildTranscoder(Class<Z> decodedClass, Class<R> transcodedClass) {
    273         return transcoderRegistry.get(decodedClass, transcodedClass);
    274     }
    275 
    276     <T, Z> DataLoadProvider<T, Z> buildDataProvider(Class<T> dataClass, Class<Z> decodedClass) {
    277         return dataLoadProviderRegistry.get(dataClass, decodedClass);
    278     }
    279 
    280     <R> Target<R> buildImageViewTarget(ImageView imageView, Class<R> transcodedClass) {
    281         return imageViewTargetFactory.buildTarget(imageView, transcodedClass);
    282     }
    283 
    284     Engine getEngine() {
    285         return engine;
    286     }
    287 
    288     CenterCrop getBitmapCenterCrop() {
    289         return bitmapCenterCrop;
    290     }
    291 
    292     FitCenter getBitmapFitCenter() {
    293         return bitmapFitCenter;
    294     }
    295 
    296     GifBitmapWrapperTransformation getDrawableCenterCrop() {
    297         return drawableCenterCrop;
    298     }
    299 
    300     GifBitmapWrapperTransformation getDrawableFitCenter() {
    301         return drawableFitCenter;
    302     }
    303 
    304     Handler getMainHandler() {
    305         return mainHandler;
    306     }
    307 
    308     DecodeFormat getDecodeFormat() {
    309         return decodeFormat;
    310     }
    311 
    312     private GenericLoaderFactory getLoaderFactory() {
    313         return loaderFactory;
    314     }
    315 
    316     /**
    317      * Pre-fills the {@link com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool} using the given sizes.
    318      *
    319      * <p>
    320      *   Enough Bitmaps are added to completely fill the pool, so most or all of the Bitmaps currently in the pool will
    321      *   be evicted. Bitmaps are allocated according to the weights of the given sizes, where each size gets
    322      *   (weight / prefillWeightSum) percent of the pool to fill.
    323      * </p>
    324      *
    325      * <p>
    326      *     Note - Pre-filling is done asynchronously using and {@link android.os.MessageQueue.IdleHandler}. Any
    327      *     currently running pre-fill will be cancelled and replaced by a call to this method.
    328      * </p>
    329      *
    330      * <p>
    331      *     This method should be used with caution, overly aggressive pre-filling is substantially worse than not
    332      *     pre-filling at all. Pre-filling should only be started in onCreate to avoid constantly clearing and
    333      *     re-filling the {@link com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool}. Rotation should be carefully
    334      *     considered as well. It may be worth calling this method only when no saved instance state exists so that
    335      *     pre-filling only happens when the Activity is first created, rather than on every rotation.
    336      * </p>
    337      *
    338      * @param bitmapAttributeBuilders The list of
    339      *     {@link com.bumptech.glide.load.engine.prefill.PreFillType.Builder Builders} representing
    340      *     individual sizes and configurations of {@link android.graphics.Bitmap}s to be pre-filled.
    341      */
    342     public void preFillBitmapPool(PreFillType.Builder... bitmapAttributeBuilders) {
    343         bitmapPreFiller.preFill(bitmapAttributeBuilders);
    344     }
    345 
    346     /**
    347      * Clears as much memory as possible.
    348      *
    349      * @see android.content.ComponentCallbacks2#onLowMemory()
    350      */
    351     public void clearMemory() {
    352         bitmapPool.clearMemory();
    353         memoryCache.clearMemory();
    354     }
    355 
    356     /**
    357      * Clears some memory with the exact amount depending on the given level.
    358      *
    359      * @see android.content.ComponentCallbacks2#onTrimMemory(int)
    360      */
    361     public void trimMemory(int level) {
    362         bitmapPool.trimMemory(level);
    363         memoryCache.trimMemory(level);
    364     }
    365 
    366     /**
    367      * Adjusts Glide's current and maximum memory usage based on the given {@link MemoryCategory}.
    368      *
    369      * <p>
    370      *     The default {@link MemoryCategory} is {@link MemoryCategory#NORMAL}. {@link MemoryCategory#HIGH} increases
    371      *     Glide's maximum memory usage by up to 50% and {@link MemoryCategory#LOW} decreases Glide's maximum memory
    372      *     usage by 50%. This method should be used to temporarily increase or decrease memory useage for a single
    373      *     Activity or part of the app. Use {@link GlideBuilder#setMemoryCache(MemoryCache)} to set a permanent
    374      *     memory size if you want to change the default.
    375      * </p>
    376      */
    377     public void setMemoryCategory(MemoryCategory memoryCategory) {
    378         memoryCache.setSizeMultiplier(memoryCategory.getMultiplier());
    379         bitmapPool.setSizeMultiplier(memoryCategory.getMultiplier());
    380     }
    381 
    382     /**
    383      * Cancel any pending loads Glide may have for the target and free any resources (such as {@link Bitmap}s) that may
    384      * have been loaded for the target so they may be reused.
    385      *
    386      * @param target The Target to cancel loads for.
    387      */
    388     public static void clear(Target<?> target) {
    389         Util.assertMainThread();
    390         Request request = target.getRequest();
    391         if (request != null) {
    392             request.clear();
    393         }
    394     }
    395 
    396     /**
    397      * Cancel any pending loads Glide may have for the target and free any resources that may have been loaded into
    398      * the target so they may be reused.
    399      *
    400      * @param target The target to cancel loads for.
    401      */
    402     public static void clear(FutureTarget<?> target) {
    403         target.clear();
    404     }
    405 
    406     /**
    407      * Cancel any pending loads Glide may have for the view and free any resources that may have been loaded for the
    408      * view.
    409      *
    410      * <p>
    411      *     Note that this will only work if {@link View#setTag(Object)} is not called on this view outside of Glide.
    412      * </p>
    413      *
    414      * @see #clear(Target).
    415      *
    416      * @param view The view to cancel loads and free resources for.
    417      * @throws IllegalArgumentException if an object other than Glide's metadata is set as the view's tag.
    418      */
    419     public static void clear(View view) {
    420         Target<?> viewTarget = new ClearTarget(view);
    421         clear(viewTarget);
    422     }
    423 
    424     /**
    425      * Use the given factory to build a {@link ModelLoader} for models of the given class. Generally the best use of
    426      * this method is to replace one of the default factories or add an implementation for other similar low level
    427      * models. Typically the {@link RequestManager#using(com.bumptech.glide.load.model.stream.StreamModelLoader)} or
    428      * {@link RequestManager#using(com.bumptech.glide.load.model.file_descriptor.FileDescriptorModelLoader)} syntax is
    429      * preferred because it directly links the model with the ModelLoader being used to load it. Any factory replaced
    430      * by the given factory will have its {@link ModelLoaderFactory#teardown()}} method called.
    431      *
    432      * <p>
    433      *     Note - If a factory already exists for the given class, it will be replaced. If that factory is not being
    434      *     used for any other model class, {@link ModelLoaderFactory#teardown()}
    435      *     will be called.
    436      * </p>
    437      *
    438      * <p>
    439      *     Note - The factory must not be an anonymous inner class of an Activity or another object that cannot be
    440      *     retained statically.
    441      * </p>
    442      *
    443      * @see RequestManager#using(com.bumptech.glide.load.model.file_descriptor.FileDescriptorModelLoader)
    444      * @see RequestManager#using(com.bumptech.glide.load.model.stream.StreamModelLoader)
    445      *
    446      * @param modelClass The model class.
    447      * @param resourceClass The resource class the model loader will translate the model type into.
    448      * @param factory The factory to use.
    449      * @param <T> The type of the model.
    450      * @param <Y> the type of the resource.
    451      */
    452     public <T, Y> void register(Class<T> modelClass, Class<Y> resourceClass, ModelLoaderFactory<T, Y> factory) {
    453         ModelLoaderFactory<T, Y> removed = loaderFactory.register(modelClass, resourceClass, factory);
    454         if (removed != null) {
    455             removed.teardown();
    456         }
    457     }
    458 
    459     /**
    460      * Removes any {@link ModelLoaderFactory} registered for the given model and resource classes if one exists. If a
    461      * {@link ModelLoaderFactory} is removed, its {@link ModelLoaderFactory#teardown()}} method will be called.
    462      *
    463      * @param modelClass The model class.
    464      * @param resourceClass The resource class.
    465      * @param <T> The type of the model.
    466      * @param <Y> The type of the resource.
    467      */
    468     public <T, Y> void unregister(Class<T> modelClass, Class<Y> resourceClass) {
    469         ModelLoaderFactory<T, Y> removed = loaderFactory.unregister(modelClass, resourceClass);
    470         if (removed != null) {
    471             removed.teardown();
    472         }
    473     }
    474 
    475     /**
    476      * Build a {@link ModelLoader} for the given model class using registered {@link ModelLoaderFactory}s.
    477      *
    478      * @see  #buildModelLoader(Object, Class, Context)
    479      * @see  #buildStreamModelLoader(Class, Context)
    480      * @see  #buildFileDescriptorModelLoader(Class, Context)
    481      *
    482      * @param modelClass The class to get a {@link ModelLoader} for.
    483      * @param resourceClass The resource class to get a {@link ModelLoader} for.
    484      * @param context Any context.
    485      * @param <T> The type of the model.
    486      * @param <Y> The type of the resource.
    487      * @return A new {@link ModelLoader} for the given model class.
    488      */
    489     public static <T, Y> ModelLoader<T, Y> buildModelLoader(Class<T> modelClass, Class<Y> resourceClass,
    490             Context context) {
    491          if (modelClass == null) {
    492             if (Log.isLoggable(TAG, Log.DEBUG)) {
    493                 Log.d(TAG, "Unable to load null model, setting placeholder only");
    494             }
    495             return null;
    496         }
    497         return Glide.get(context).getLoaderFactory().buildModelLoader(modelClass, resourceClass);
    498     }
    499 
    500     /**
    501      * A convenience method to build a {@link ModelLoader} for a given model object using registered
    502      * {@link ModelLoaderFactory}s.
    503      *
    504      * @see #buildModelLoader(Class, Class, Context)
    505      *
    506      * @param model A non null model object whose class we will get a {@link ModelLoader} for.
    507      * @param resourceClass The resource class to get a {@link ModelLoader} for.
    508      * @param context Any context.
    509      * @param <T> The type of the model.
    510      * @param <Y> The type of the resource.
    511      * @return A new {@link ModelLoader} for the given model and resource classes, or null if model is null.
    512      */
    513     @SuppressWarnings("unchecked")
    514     public static <T, Y> ModelLoader<T, Y> buildModelLoader(T model, Class<Y> resourceClass, Context context) {
    515         return buildModelLoader(model != null ? (Class<T>) model.getClass() : null, resourceClass, context);
    516     }
    517 
    518     /**
    519      * A method to build a {@link ModelLoader} for the given model that produces {@link InputStream}s using a registered
    520      * factory.
    521      *
    522      * @see #buildModelLoader(Class, Class, android.content.Context)
    523      */
    524     public static <T> ModelLoader<T, InputStream> buildStreamModelLoader(Class<T> modelClass, Context context) {
    525         return buildModelLoader(modelClass, InputStream.class, context);
    526     }
    527 
    528     /**
    529      * A method to build a {@link ModelLoader} for the given model that produces {@link InputStream}s using a registered
    530      * factory.
    531      *
    532      * @see #buildModelLoader(Object, Class, Context)
    533      */
    534     public static <T> ModelLoader<T, InputStream> buildStreamModelLoader(T model, Context context) {
    535         return buildModelLoader(model, InputStream.class, context);
    536     }
    537 
    538     /**
    539      * A method to build a {@link ModelLoader} for the given model class that produces
    540      * {@link ParcelFileDescriptor}s using a registered factory.
    541      *
    542      * @see #buildModelLoader(Class, Class, android.content.Context)
    543      */
    544     public static <T> ModelLoader<T, ParcelFileDescriptor> buildFileDescriptorModelLoader(Class<T> modelClass,
    545             Context context) {
    546         return buildModelLoader(modelClass, ParcelFileDescriptor.class, context);
    547     }
    548 
    549     /**
    550      * A method to build a {@link ModelLoader} for the given model class that produces
    551      * {@link ParcelFileDescriptor}s using a registered factory.
    552      *
    553      * @see #buildModelLoader(Object, Class, android.content.Context)
    554      */
    555     public static <T> ModelLoader<T, ParcelFileDescriptor> buildFileDescriptorModelLoader(T model, Context context) {
    556         return buildModelLoader(model, ParcelFileDescriptor.class, context);
    557     }
    558 
    559     /**
    560      * Begin a load with Glide by passing in a context.
    561      *
    562      * <p>
    563      *     Any requests started using a context will only have the application level options applied and will not be
    564      *     started or stopped based on lifecycle events. In general, loads should be started at the level the result
    565      *     will be used in. If the resource will be used in a view in a child fragment,
    566      *     the load should be started with {@link #with(android.app.Fragment)}} using that child fragment. Similarly,
    567      *     if the resource will be used in a view in the parent fragment, the load should be started with
    568      *     {@link #with(android.app.Fragment)} using the parent fragment. In the same vein, if the resource will be used
    569      *     in a view in an activity, the load should be started with {@link #with(android.app.Activity)}}.
    570      * </p>
    571      *
    572      * <p>
    573      *     This method is appropriate for resources that will be used outside of the normal fragment or activity
    574      *     lifecycle (For example in services, or for notification thumbnails).
    575      * </p>
    576      *
    577      * @see #with(android.app.Activity)
    578      * @see #with(android.app.Fragment)
    579      * @see #with(android.support.v4.app.Fragment)
    580      * @see #with(android.support.v4.app.FragmentActivity)
    581      *
    582      * @param context Any context, will not be retained.
    583      * @return A RequestManager for the top level application that can be used to start a load.
    584      */
    585     public static RequestManager with(Context context) {
    586         RequestManagerRetriever retriever = RequestManagerRetriever.get();
    587         return retriever.get(context);
    588     }
    589 
    590     /**
    591      * Begin a load with Glide that will be tied to the given {@link android.app.Activity}'s lifecycle and that uses the
    592      * given {@link Activity}'s default options.
    593      *
    594      * @param activity The activity to use.
    595      * @return A RequestManager for the given activity that can be used to start a load.
    596      */
    597     public static RequestManager with(Activity activity) {
    598         RequestManagerRetriever retriever = RequestManagerRetriever.get();
    599         return retriever.get(activity);
    600     }
    601 
    602     /**
    603      * Begin a load with Glide that will tied to the give {@link android.support.v4.app.FragmentActivity}'s lifecycle
    604      * and that uses the given {@link android.support.v4.app.FragmentActivity}'s default options.
    605      *
    606      * @param activity The activity to use.
    607      * @return A RequestManager for the given FragmentActivity that can be used to start a load.
    608      */
    609     public static RequestManager with(FragmentActivity activity) {
    610         RequestManagerRetriever retriever = RequestManagerRetriever.get();
    611         return retriever.get(activity);
    612     }
    613 
    614     /**
    615      * Begin a load with Glide that will be tied to the given {@link android.app.Fragment}'s lifecycle and that uses
    616      * the given {@link android.app.Fragment}'s default options.
    617      *
    618      * @param fragment The fragment to use.
    619      * @return A RequestManager for the given Fragment that can be used to start a load.
    620      */
    621     @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    622     public static RequestManager with(android.app.Fragment fragment) {
    623         RequestManagerRetriever retriever = RequestManagerRetriever.get();
    624         return retriever.get(fragment);
    625     }
    626 
    627     /**
    628      * Begin a load with Glide that will be tied to the given {@link android.support.v4.app.Fragment}'s lifecycle and
    629      * that uses the given {@link android.support.v4.app.Fragment}'s default options.
    630      *
    631      * @param fragment The fragment to use.
    632      * @return A RequestManager for the given Fragment that can be used to start a load.
    633      */
    634     public static RequestManager with(Fragment fragment) {
    635         RequestManagerRetriever retriever = RequestManagerRetriever.get();
    636         return retriever.get(fragment);
    637     }
    638 
    639     private static class ClearTarget extends ViewTarget<View, Object> {
    640         public ClearTarget(View view) {
    641             super(view);
    642         }
    643 
    644         @Override
    645         public void onLoadStarted(Drawable placeholder) {
    646             // Do nothing.
    647         }
    648 
    649         @Override
    650         public void onLoadFailed(Exception e, Drawable errorDrawable) {
    651             // Do nothing.
    652         }
    653 
    654         @Override
    655         public void onResourceReady(Object resource, GlideAnimation<? super Object> glideAnimation) {
    656             // Do nothing.
    657         }
    658 
    659         @Override
    660         public void onLoadCleared(Drawable placeholder) {
    661             // Do nothing.
    662         }
    663     }
    664 }
    665