Home | History | Annotate | Download | only in glide
      1 package com.bumptech.glide;
      2 
      3 import android.content.Context;
      4 import android.net.Uri;
      5 import android.os.Handler;
      6 import android.os.Looper;
      7 import android.os.ParcelFileDescriptor;
      8 
      9 import com.bumptech.glide.load.Key;
     10 import com.bumptech.glide.load.engine.DiskCacheStrategy;
     11 import com.bumptech.glide.load.model.ModelLoader;
     12 import com.bumptech.glide.load.model.file_descriptor.FileDescriptorModelLoader;
     13 import com.bumptech.glide.load.model.stream.MediaStoreStreamLoader;
     14 import com.bumptech.glide.load.model.stream.StreamByteArrayLoader;
     15 import com.bumptech.glide.load.model.stream.StreamModelLoader;
     16 import com.bumptech.glide.manager.ConnectivityMonitor;
     17 import com.bumptech.glide.manager.ConnectivityMonitorFactory;
     18 import com.bumptech.glide.manager.Lifecycle;
     19 import com.bumptech.glide.manager.LifecycleListener;
     20 import com.bumptech.glide.manager.RequestTracker;
     21 import com.bumptech.glide.signature.ApplicationVersionSignature;
     22 import com.bumptech.glide.signature.MediaStoreSignature;
     23 import com.bumptech.glide.signature.StringSignature;
     24 import com.bumptech.glide.util.Util;
     25 
     26 import java.io.File;
     27 import java.io.InputStream;
     28 import java.net.URL;
     29 import java.util.UUID;
     30 
     31 /**
     32  * A class for managing and starting requests for Glide. Can use activity, fragment and connectivity lifecycle events to
     33  * intelligently stop, start, and restart requests. Retrieve either by instantiating a new object, or to take advantage
     34  * built in Activity and Fragment lifecycle handling, use the static Glide.load methods with your Fragment or Activity.
     35  *
     36  * @see Glide#with(android.app.Activity)
     37  * @see Glide#with(android.support.v4.app.FragmentActivity)
     38  * @see Glide#with(android.app.Fragment)
     39  * @see Glide#with(android.support.v4.app.Fragment)
     40  * @see Glide#with(Context)
     41  */
     42 public class RequestManager implements LifecycleListener {
     43     private final Context context;
     44     private final Lifecycle lifecycle;
     45     private final RequestTracker requestTracker;
     46     private final Glide glide;
     47     private final OptionsApplier optionsApplier;
     48     private DefaultOptions options;
     49 
     50     public RequestManager(Context context, Lifecycle lifecycle) {
     51         this(context, lifecycle, new RequestTracker(), new ConnectivityMonitorFactory());
     52     }
     53 
     54     RequestManager(Context context, final Lifecycle lifecycle, RequestTracker requestTracker,
     55             ConnectivityMonitorFactory factory) {
     56         this.context = context.getApplicationContext();
     57         this.lifecycle = lifecycle;
     58         this.requestTracker = requestTracker;
     59         this.glide = Glide.get(context);
     60         this.optionsApplier = new OptionsApplier();
     61 
     62         ConnectivityMonitor connectivityMonitor = factory.build(context,
     63                 new RequestManagerConnectivityListener(requestTracker));
     64 
     65         // If we're the application level request manager, we may be created on a background thread. In that case we
     66         // cannot risk synchronously pausing or resuming requests, so we hack around the issue by delaying adding
     67         // ourselves as a lifecycle listener by posting to the main thread. This should be entirely safe.
     68         if (Util.isOnBackgroundThread()) {
     69             new Handler(Looper.getMainLooper()).post(new Runnable() {
     70                 @Override
     71                 public void run() {
     72                     lifecycle.addListener(RequestManager.this);
     73                 }
     74             });
     75         } else {
     76             lifecycle.addListener(this);
     77         }
     78         lifecycle.addListener(connectivityMonitor);
     79     }
     80 
     81     /**
     82      * An interface that allows a default set of options to be applied to all requests started from an
     83      * {@link com.bumptech.glide.RequestManager}.
     84      */
     85     public interface DefaultOptions {
     86         /**
     87          * Allows the implementor to apply some options to the given request.
     88          *
     89          * @param requestBuilder The request builder being used to construct the load.
     90          * @param <T> The type of the model.
     91          */
     92         <T> void apply(GenericRequestBuilder<T, ?, ?, ?> requestBuilder);
     93     }
     94 
     95     /**
     96      * Sets an interface that can apply some default options to all Requests started using this {@link RequestManager}.
     97      *
     98      * <p>
     99      *     Note - These options will be retained for the life the of this {@link com.bumptech.glide.RequestManager}
    100      *     so be wary of using
    101      *     {@link com.bumptech.glide.GenericRequestBuilder#listener(com.bumptech.glide.request.RequestListener)}} when
    102      *     starting requests using an {@link android.content.Context} or {@link android.app.Application} to avoid
    103      *     leaking memory. Any option that does not use an anonymous inner class is generally safe.
    104      * </p>
    105      *
    106      * @param options The default options to apply to all requests.
    107      */
    108     public void setDefaultOptions(DefaultOptions options) {
    109         this.options = options;
    110     }
    111 
    112     /**
    113      * Returns true if loads for this {@link RequestManager} are currently paused.
    114      *
    115      * @see #pauseRequests()
    116      * @see #resumeRequests()
    117      */
    118     public boolean isPaused() {
    119         Util.assertMainThread();
    120         return requestTracker.isPaused();
    121     }
    122 
    123     /**
    124      * Cancels any in progress loads, but does not clear resources of completed loads.
    125      *
    126      * @see #isPaused()
    127      * @see #resumeRequests()
    128      */
    129     public void pauseRequests() {
    130         Util.assertMainThread();
    131         requestTracker.pauseRequests();
    132     }
    133 
    134     /**
    135      * Restarts any loads that have not yet completed.
    136      *
    137      * @see #isPaused()
    138      * @see #pauseRequests()
    139      */
    140     public void resumeRequests() {
    141         Util.assertMainThread();
    142         requestTracker.resumeRequests();
    143     }
    144 
    145     /**
    146      * Lifecycle callback that registers for connectivity events (if the android.permission.ACCESS_NETWORK_STATE
    147      * permission is present) and restarts failed or paused requests.
    148      */
    149     @Override
    150     public void onStart() {
    151         // onStart might not be called because this object may be created after the fragment/activity's onStart method.
    152         resumeRequests();
    153     }
    154 
    155     /**
    156      * Lifecycle callback that unregisters for connectivity events (if the android.permission.ACCESS_NETWORK_STATE
    157      * permission is present) and pauses in progress loads.
    158      */
    159     @Override
    160     public void onStop() {
    161         pauseRequests();
    162     }
    163 
    164     /**
    165      * Lifecycle callback that cancels all in progress requests and clears and recycles resources for all completed
    166      * requests.
    167      */
    168     @Override
    169     public void onDestroy() {
    170         requestTracker.clearRequests();
    171     }
    172 
    173     /**
    174      * Returns a request builder that uses the given {@link com.bumptech.glide.load.model.ModelLoader} to fetch a
    175      * generic data type.
    176      *
    177      * <p>
    178      *     Warning - This is an experimental api that may change without a change in major version.
    179      * </p>
    180      *
    181      * @param modelLoader The {@link ModelLoader} class to use to load the model.
    182      * @param dataClass The type of data the {@link ModelLoader} will load.
    183      * @param <A> The type of the model to be loaded.
    184      * @param <T> The type of the data to be loaded from the mode.
    185      */
    186     public <A, T> GenericModelRequest<A, T> using(ModelLoader<A, T> modelLoader, Class<T> dataClass) {
    187         return new GenericModelRequest<A, T>(modelLoader, dataClass);
    188     }
    189 
    190     /**
    191      * Returns a request builder that uses the given {@link com.bumptech.glide.load.model.stream.StreamModelLoader} to
    192      * fetch an {@link InputStream} for loading images.
    193      *
    194      * @param modelLoader The model loader to use.
    195      * @param <T> The type of the model.
    196      */
    197     public <T> ImageModelRequest<T> using(final StreamModelLoader<T> modelLoader) {
    198         return new ImageModelRequest<T>(modelLoader);
    199     }
    200 
    201     /**
    202      * Returns a request builder that uses the given
    203      * {@link com.bumptech.glide.load.model.stream.StreamByteArrayLoader} to fetch an {@link java.io.InputStream} for
    204      * loading Bitmaps.
    205      *
    206      * @param modelLoader The byte array loader.
    207      */
    208     public ImageModelRequest<byte[]> using(StreamByteArrayLoader modelLoader) {
    209         return new ImageModelRequest<byte[]>(modelLoader);
    210     }
    211 
    212     /**
    213      * Returns a new request builder that uses the given {@link ModelLoader} to fetch a
    214      * {@link ParcelFileDescriptor} for loading video thumbnails.
    215      *
    216      * @param modelLoader The model loader to use.
    217      * @param <T> The type of the model.
    218      */
    219     public <T> VideoModelRequest<T> using(final FileDescriptorModelLoader<T> modelLoader) {
    220         return new VideoModelRequest<T>(modelLoader);
    221     }
    222 
    223     /**
    224      * Returns a request builder to load the given {@link java.lang.String}.
    225      * signature.
    226      *
    227      * @see #fromString()
    228      * @see #load(Object)
    229      *
    230      * @param string A file path, or a uri or url handled by {@link com.bumptech.glide.load.model.UriLoader}.
    231      */
    232     public DrawableTypeRequest<String> load(String string) {
    233         return (DrawableTypeRequest<String>) fromString().load(string);
    234     }
    235 
    236     /**
    237      * Returns a request builder that loads data from {@link String}s using an empty signature.
    238      *
    239      * <p>
    240      *     Note - this method caches data using only the given String as the cache key. If the data is a Uri outside of
    241      *     your control, or you otherwise expect the data represented by the given String to change without the String
    242      *     identifier changing, Consider using
    243      *     {@link com.bumptech.glide.GenericRequestBuilder#signature(com.bumptech.glide.load.Key)} to mixin a signature
    244      *     you create that identifies the data currently at the given String that will invalidate the cache if that data
    245      *     changes. Alternatively, using {@link com.bumptech.glide.load.engine.DiskCacheStrategy#NONE} and/or
    246      *     {@link com.bumptech.glide.DrawableRequestBuilder#skipMemoryCache(boolean)} may be appropriate.
    247      * </p>
    248      *
    249      * @see #from(Class)
    250      * @see #load(String)
    251      */
    252     public DrawableTypeRequest<String> fromString() {
    253         return loadGeneric(String.class);
    254     }
    255 
    256     /**
    257      * Returns a request builder to load the given {@link Uri}.
    258      *
    259      * @see #fromUri()
    260      * @see #load(Object)
    261      *
    262      * @param uri The Uri representing the image. Must be of a type handled by
    263      * {@link com.bumptech.glide.load.model.UriLoader}.
    264      */
    265     public DrawableTypeRequest<Uri> load(Uri uri) {
    266         return (DrawableTypeRequest<Uri>) fromUri().load(uri);
    267     }
    268 
    269     /**
    270      * Returns a request builder to load data from {@link android.net.Uri}s using no signature.
    271      *
    272      * <p>
    273      *     Note - this method caches data at Uris using only the Uri itself as the cache key. The data represented by
    274      *     Uris from some content providers may change without the Uri changing, which means using this method
    275      *     can lead to displaying stale data. Consider using
    276      *     {@link com.bumptech.glide.GenericRequestBuilder#signature(com.bumptech.glide.load.Key)} to mixin a signature
    277      *     you create based on the data at the given Uri that will invalidate the cache if that data changes.
    278      *     Alternatively, using {@link com.bumptech.glide.load.engine.DiskCacheStrategy#NONE} and/or
    279      *     {@link com.bumptech.glide.DrawableRequestBuilder#skipMemoryCache(boolean)} may be appropriate.
    280      * </p>
    281      *
    282      * @see #from(Class)
    283      * @see #loadFromMediaStore(android.net.Uri)
    284      * @see #loadFromMediaStore(android.net.Uri, String, long, int)
    285      * @see com.bumptech.glide.GenericRequestBuilder#signature(com.bumptech.glide.load.Key)
    286      */
    287     public DrawableTypeRequest<Uri> fromUri() {
    288         return loadGeneric(Uri.class);
    289     }
    290 
    291     /**
    292      * Returns a request builder that uses {@link android.provider.MediaStore.Images.Thumbnails} and
    293      * {@link android.provider.MediaStore.Video.Thumbnails} to retrieve pre-generated thumbnails for the given uri if
    294      * available and uses the given additional data to build a unique signature for cache invalidation.
    295      *
    296      * @see #loadFromMediaStore(android.net.Uri)
    297      * @see #load(android.net.Uri)
    298      * @see com.bumptech.glide.GenericRequestBuilder#signature(com.bumptech.glide.load.Key)
    299      * @see com.bumptech.glide.signature.MediaStoreSignature
    300      *
    301      * @deprecated Use {@link #loadFromMediaStore(android.net.Uri)},
    302      * {@link com.bumptech.glide.signature.MediaStoreSignature}, and
    303      * {@link com.bumptech.glide.DrawableRequestBuilder#signature(com.bumptech.glide.load.Key)} instead. Scheduled to be
    304      * removed in Glide 4.0.
    305      * @param uri The uri representing the media.
    306      * @param mimeType The mime type of the media store media. Ok to default to empty string "". See
    307      *      {@link android.provider.MediaStore.Images.ImageColumns#MIME_TYPE} or
    308      *      {@link android.provider.MediaStore.Video.VideoColumns#MIME_TYPE}.
    309      * @param dateModified The date modified time of the media store media. Ok to default to 0. See
    310      *      {@link android.provider.MediaStore.Images.ImageColumns#DATE_MODIFIED} or
    311      *      {@link android.provider.MediaStore.Video.VideoColumns#DATE_MODIFIED}.
    312      * @param orientation The orientation of the media store media. Ok to default to 0. See
    313      *      {@link android.provider.MediaStore.Images.ImageColumns#ORIENTATION}.
    314      */
    315     @Deprecated
    316     public DrawableTypeRequest<Uri> loadFromMediaStore(Uri uri, String mimeType, long dateModified, int orientation) {
    317         Key signature = new MediaStoreSignature(mimeType, dateModified, orientation);
    318         return (DrawableTypeRequest<Uri>) loadFromMediaStore(uri).signature(signature);
    319     }
    320 
    321     /**
    322      * Returns a request builder to load the given media store {@link android.net.Uri}.
    323      *
    324      * @see #fromMediaStore()
    325      * @see #load(Object)
    326      *
    327      * @param uri The uri representing the media.
    328      */
    329     public DrawableTypeRequest<Uri> loadFromMediaStore(Uri uri) {
    330         return (DrawableTypeRequest<Uri>) fromMediaStore().load(uri);
    331     }
    332 
    333     /**
    334      * Returns a request builder that uses {@link android.provider.MediaStore.Images.Thumbnails} and
    335      * {@link android.provider.MediaStore.Video.Thumbnails} to retrieve pre-generated thumbnails for
    336      * {@link android.net.Uri}s.
    337      *
    338      * <p>
    339      *  Falls back to the registered {@link com.bumptech.glide.load.model.ModelLoaderFactory} registered for
    340      *  {@link Uri}s if the given uri is not a media store uri or if no pre-generated thumbnail exists for the given
    341      *  uri.
    342      * </p>
    343      *
    344      * <p>
    345      *     Note - This method by default caches data using the given Uri as the key. Since content in the media store
    346      *     can change at any time, you should use
    347      *     {@link com.bumptech.glide.GenericRequestBuilder#signature(com.bumptech.glide.load.Key)} to mix in some
    348      *     additional data identifying the current state of the Uri, preferably using
    349      *     {@link com.bumptech.glide.signature.MediaStoreSignature}. Alternatively consider avoiding the memory and
    350      *     disk caches entirely using
    351      *     {@link GenericRequestBuilder#diskCacheStrategy(com.bumptech.glide.load.engine.DiskCacheStrategy)}
    352      *     and {@link com.bumptech.glide.load.engine.DiskCacheStrategy#NONE} and/or
    353      *     {@link com.bumptech.glide.GenericRequestBuilder#skipMemoryCache(boolean)}.
    354      * </p>
    355      *
    356      * @see #from(Class)
    357      * @see #loadFromMediaStore(android.net.Uri, String, long, int)
    358      * @see #load(android.net.Uri)
    359      * @see com.bumptech.glide.signature.MediaStoreSignature
    360      */
    361     public DrawableTypeRequest<Uri> fromMediaStore() {
    362         ModelLoader<Uri, InputStream> genericStreamLoader = Glide.buildStreamModelLoader(Uri.class, context);
    363         ModelLoader<Uri, InputStream> mediaStoreLoader = new MediaStoreStreamLoader(context, genericStreamLoader);
    364         ModelLoader<Uri, ParcelFileDescriptor> fileDescriptorModelLoader =
    365                 Glide.buildFileDescriptorModelLoader(Uri.class, context);
    366 
    367         return optionsApplier.apply(new DrawableTypeRequest<Uri>(Uri.class, mediaStoreLoader,
    368                 fileDescriptorModelLoader, context, glide, requestTracker, lifecycle, optionsApplier));
    369     }
    370 
    371     /**
    372      * Returns a request builder to load the given {@link File}.
    373      *
    374      * @see #fromFile()
    375      * @see #load(Object)
    376      *
    377      * @param file The File containing the image
    378      */
    379     public DrawableTypeRequest<File> load(File file) {
    380         return (DrawableTypeRequest<File>) fromFile().load(file);
    381     }
    382 
    383     /**
    384      * Returns a request builder that uses the {@link com.bumptech.glide.load.model.ModelLoaderFactory} currently
    385      * registered for {@link File} to load the image represented by the given {@link File}. Defaults to
    386      * {@link com.bumptech.glide.load.model.stream.StreamFileLoader.Factory} and
    387      * {@link com.bumptech.glide.load.model.stream.StreamFileLoader} to load images from {@link File}s.
    388      *
    389      *  <p>
    390      *     Note - this method caches data for Files using only the file path itself as the cache key. The data in the
    391      *     File can change so using this method can lead to displaying stale data. If you expect the data in the File to
    392      *     change, Consider using
    393      *     {@link com.bumptech.glide.GenericRequestBuilder#signature(com.bumptech.glide.load.Key)} to mixin a signature
    394      *     you create that identifies the data currently in the File that will invalidate the cache if that data
    395      *     changes. Alternatively, using {@link com.bumptech.glide.load.engine.DiskCacheStrategy#NONE} and/or
    396      *     {@link com.bumptech.glide.DrawableRequestBuilder#skipMemoryCache(boolean)} may be appropriate.
    397      * </p>
    398      *
    399      * @see #load(java.io.File)
    400      * @see #from(Class)
    401      */
    402     public DrawableTypeRequest<File> fromFile() {
    403         return loadGeneric(File.class);
    404     }
    405 
    406     /**
    407      * Returns a request builder to load the given resource id.
    408      *
    409      * @see #fromResource()
    410      * @see #load(Object)
    411      *
    412      * @param resourceId the id of the resource containing the image
    413      */
    414     public DrawableTypeRequest<Integer> load(Integer resourceId) {
    415         return (DrawableTypeRequest<Integer>) fromResource().load(resourceId);
    416     }
    417 
    418     /**
    419      * Returns a request builder that uses the {@link com.bumptech.glide.load.model.ModelLoaderFactory} currently
    420      * registered for {@link Integer} to load the image represented by the given {@link Integer} resource id. Defaults
    421      * to {@link com.bumptech.glide.load.model.stream.StreamResourceLoader.Factory} and
    422      * {@link com.bumptech.glide.load.model.stream.StreamResourceLoader} to load resource id models.
    423      *
    424      * <p>
    425      *     By default this method adds a version code based signature to the cache key used to cache this resource in
    426      *     Glide. This signature is sufficient to guarantee that end users will see the most up to date versions of
    427      *     your Drawables, but during development if you do not increment your version code before each install and
    428      *     you replace a Drawable with different data without changing the Drawable name, you may see inconsistent
    429      *     cached data. To get around this, consider using {@link com.bumptech.glide.load.engine.DiskCacheStrategy#NONE}
    430      *     via {@link GenericRequestBuilder#diskCacheStrategy(com.bumptech.glide.load.engine.DiskCacheStrategy)}
    431      *     during development, and re-enabling the default
    432      *     {@link com.bumptech.glide.load.engine.DiskCacheStrategy#RESULT} for release builds.
    433      * </p>
    434      *
    435      * @see #from(Class)
    436      * @see #load(Integer)
    437      * @see com.bumptech.glide.signature.ApplicationVersionSignature
    438      * @see com.bumptech.glide.GenericRequestBuilder#signature(com.bumptech.glide.load.Key)
    439      */
    440     public DrawableTypeRequest<Integer> fromResource() {
    441         return (DrawableTypeRequest<Integer>) loadGeneric(Integer.class)
    442                 .signature(ApplicationVersionSignature.obtain(context));
    443     }
    444 
    445     /**
    446      * Returns a request builder to load the given {@link URL}.
    447      *
    448      * @see #fromUrl()
    449      * @see #load(Object)
    450      *
    451      * @deprecated The {@link java.net.URL} class has
    452      * <a href="http://goo.gl/c4hHNu">a number of performance problems</a> and should generally be avoided when
    453      * possible. Prefer {@link #load(android.net.Uri)} or {@link #load(String)}.
    454      * @param url The URL representing the image.
    455      */
    456     @Deprecated
    457     public DrawableTypeRequest<URL> load(URL url) {
    458         return (DrawableTypeRequest<URL>) fromUrl().load(url);
    459     }
    460 
    461     /**
    462      * Returns a request builder that uses the {@link com.bumptech.glide.load.model.ModelLoaderFactory} currently
    463      * registered for {@link URL} to load the image represented by the given {@link URL}. Defaults to
    464      * {@link com.bumptech.glide.load.model.stream.HttpUrlGlideUrlLoader} and
    465      * {@link com.bumptech.glide.load.data.HttpUrlFetcher} to load {@link java.net.URL} models.
    466      *
    467      * @see #from(Class)
    468      * @see #load(java.net.URL)
    469      *
    470      * @deprecated The {@link java.net.URL} class has
    471      * <a href="http://goo.gl/c4hHNu">a number of performance problems</a> and should generally be avoided when
    472      * possible. Prefer {@link #load(android.net.Uri)} or {@link #load(String)}.
    473      */
    474     @Deprecated
    475     public DrawableTypeRequest<URL> fromUrl() {
    476         return loadGeneric(URL.class);
    477     }
    478 
    479     /**
    480      * Returns a request builder that uses a {@link StreamByteArrayLoader} to load an image from the given byte array.
    481      *
    482      *
    483      * <p>
    484      *     Note - by default loads for bytes are not cached in either the memory or the disk cache.
    485      * </p>
    486      *
    487      * @see #load(byte[])
    488      *
    489      * @deprecated Use {@link #load(byte[])} along with
    490      * {@link com.bumptech.glide.GenericRequestBuilder#signature(com.bumptech.glide.load.Key)} instead. Scheduled to be
    491      * removed in Glide 4.0.
    492      * @param model The data to load.
    493      * @param id A unique id that identifies the image represented by the model suitable for use as a cache key
    494      *           (url, filepath etc). If there is no suitable id, use {@link #load(byte[])} instead.
    495      */
    496     @Deprecated
    497     public DrawableTypeRequest<byte[]> load(byte[] model, final String id) {
    498         return (DrawableTypeRequest<byte[]>) load(model).signature(new StringSignature(id));
    499     }
    500 
    501     /**
    502      * Returns a request to load the given byte array.
    503      *
    504      * @see #fromBytes()
    505      * @see #load(Object)
    506      *
    507      * @param model the data to load.
    508      */
    509     public DrawableTypeRequest<byte[]> load(byte[] model) {
    510         return (DrawableTypeRequest<byte[]>) fromBytes().load(model);
    511     }
    512 
    513     /**
    514      * Returns a request builder that uses {@link com.bumptech.glide.load.model.stream.StreamByteArrayLoader} to load
    515      * images from byte arrays.
    516      *
    517      * <p>
    518      *     Note - by default loads for bytes are not cached in either the memory or the disk cache.
    519      * </p>
    520      *
    521      * @see #from(Class)
    522      * @see #load(byte[])
    523      */
    524     public DrawableTypeRequest<byte[]> fromBytes() {
    525         return (DrawableTypeRequest<byte[]>) loadGeneric(byte[].class)
    526                 .signature(new StringSignature(UUID.randomUUID().toString()))
    527                 .diskCacheStrategy(DiskCacheStrategy.NONE)
    528                 .skipMemoryCache(true /*skipMemoryCache*/);
    529     }
    530 
    531     /**
    532      * Returns a request builder that uses the {@link com.bumptech.glide.load.model.ModelLoaderFactory}s currently
    533      * registered for the given model class for {@link InputStream}s and {@link ParcelFileDescriptor}s to load a
    534      * thumbnail from either the image or the video represented by the given model.
    535      *
    536      * <p>
    537      *     Note - for maximum efficiency, consider using {@link #from(Class)}} to avoid repeatedly allocating builder
    538      *     objects.
    539      * </p>
    540      *
    541      * @see #from(Class)
    542      *
    543      * @param model The model the load.
    544      * @param <T> The type of the model to load.
    545      */
    546     public <T> DrawableTypeRequest<T> load(T model) {
    547         return (DrawableTypeRequest<T>) loadGeneric(getSafeClass(model)).load(model);
    548     }
    549 
    550     /**
    551      * Returns a request builder that can be used for multiple loads that uses the
    552      * {@link com.bumptech.glide.load.model.ModelLoaderFactory}s registered for the given model class for
    553      * {@link java.io.InputStream}s and {@link android.os.ParcelFileDescriptor}s to load a thumbnail from objects of
    554      * the given modelClass.
    555      *
    556      * <p>
    557      *     Note - you must use {@link com.bumptech.glide.DrawableRequestBuilder#load(Object)}} to set a concrete model
    558      *     to be loaded before calling
    559      *     {@link com.bumptech.glide.DrawableRequestBuilder#into(com.bumptech.glide.request.target.Target)}. You may
    560      *     also use this object for repeated loads by calling <code>request.load(model).into(target)</code>. You may
    561      *     also adjust the options after calling {@link com.bumptech.glide.DrawableRequestBuilder#load(Object)}} and/or
    562      *     {@link com.bumptech.glide.DrawableRequestBuilder#into(com.bumptech.glide.request.target.Target)}}. However,
    563      *     keep in mind that any changes in options will apply to all future loads.
    564      * </p>
    565      *
    566      * @param modelClass The class of model requests built by this class will load data from.
    567      * @param <T> The type of the model.
    568      */
    569     public <T> DrawableTypeRequest<T> from(Class<T> modelClass) {
    570         return loadGeneric(modelClass);
    571     }
    572 
    573     private <T> DrawableTypeRequest<T> loadGeneric(Class<T> modelClass) {
    574         ModelLoader<T, InputStream> streamModelLoader = Glide.buildStreamModelLoader(modelClass, context);
    575         ModelLoader<T, ParcelFileDescriptor> fileDescriptorModelLoader =
    576                 Glide.buildFileDescriptorModelLoader(modelClass, context);
    577         if (modelClass != null && streamModelLoader == null && fileDescriptorModelLoader == null) {
    578             throw new IllegalArgumentException("Unknown type " + modelClass + ". You must provide a Model of a type for"
    579                     + " which there is a registered ModelLoader, if you are using a custom model, you must first call"
    580                     + " Glide#register with a ModelLoaderFactory for your custom model class");
    581         }
    582 
    583         return optionsApplier.apply(
    584                 new DrawableTypeRequest<T>(modelClass, streamModelLoader, fileDescriptorModelLoader, context,
    585                         glide, requestTracker, lifecycle, optionsApplier));
    586     }
    587 
    588     @SuppressWarnings("unchecked")
    589     private static <T> Class<T> getSafeClass(T model) {
    590         return model != null ? (Class<T>) model.getClass() : null;
    591     }
    592 
    593     /**
    594      * A helper class for building requests with custom {@link ModelLoader}s that translate models to
    595      * {@link ParcelFileDescriptor} resources for loading video thumbnails.
    596      *
    597      * @param <T> The type of the model.
    598      */
    599     public final class VideoModelRequest<T> {
    600         private final ModelLoader<T, ParcelFileDescriptor> loader;
    601 
    602         VideoModelRequest(ModelLoader<T, ParcelFileDescriptor> loader) {
    603             this.loader = loader;
    604         }
    605 
    606         public DrawableTypeRequest<T> load(T model) {
    607             return (DrawableTypeRequest<T>) optionsApplier.apply(new DrawableTypeRequest<T>(getSafeClass(model), null,
    608                     loader, context, glide, requestTracker, lifecycle, optionsApplier))
    609                     .load(model);
    610         }
    611     }
    612 
    613     /**
    614      * A helper class for building requests with custom {@link ModelLoader}s that translate models to
    615      * {@link InputStream} resources for loading images.
    616      *
    617      * @param <T> The type of the model.
    618      */
    619     public final class ImageModelRequest<T> {
    620         private final ModelLoader<T, InputStream> loader;
    621 
    622         ImageModelRequest(ModelLoader<T, InputStream> loader) {
    623             this.loader = loader;
    624         }
    625 
    626         /**
    627          * Returns a request builder that uses the provided {@link com.bumptech.glide.load.model.ModelLoader} to load
    628          * images from an {@link java.io.InputStream}s obtained from models of the given model class.
    629          *
    630          * @param modelClass The class of model to load images from.
    631          */
    632         public DrawableTypeRequest<T> from(Class<T> modelClass) {
    633             return optionsApplier.apply(new DrawableTypeRequest<T>(modelClass, loader, null, context, glide,
    634                     requestTracker, lifecycle, optionsApplier));
    635         }
    636 
    637         /**
    638          * Returns a request builder that uses the provided {@link com.bumptech.glide.load.model.ModelLoader} to load
    639          * an image from an {@link java.io.InputStream} obtained from the given model.
    640          *
    641          * @see #from(Class)
    642          *
    643          * @param model The model to load an image from.
    644          */
    645         public DrawableTypeRequest<T> load(T model) {
    646             return (DrawableTypeRequest<T>) from(getSafeClass(model)).load(model);
    647         }
    648     }
    649 
    650     /**
    651      * A helper class for building requests with custom {@link ModelLoader}s that requires the user to provide a
    652      * specific model.
    653      *
    654      * @param <A> The type of the model.
    655      * @param <T> The type of data the {@link com.bumptech.glide.load.model.ModelLoader} provides an
    656      * {@link com.bumptech.glide.load.data.DataFetcher} to convert the model to.
    657      */
    658     public final class GenericModelRequest<A, T> {
    659         private final ModelLoader<A, T> modelLoader;
    660         private final Class<T> dataClass;
    661 
    662         GenericModelRequest(ModelLoader<A, T> modelLoader, Class<T> dataClass) {
    663             this.modelLoader = modelLoader;
    664             this.dataClass = dataClass;
    665         }
    666 
    667         /**
    668          * Sets the type of model that will be loaded.
    669          *
    670          * @param modelClass the class of model to use.
    671          * @return A request builder
    672          */
    673         public GenericTypeRequest from(Class<A> modelClass) {
    674             return new GenericTypeRequest(modelClass);
    675         }
    676 
    677         /**
    678          * Sets the specific model that will be loaded.
    679          *
    680          * @param model The model to use.
    681          * @return A request builder.
    682          */
    683         public GenericTypeRequest load(A model) {
    684             return new GenericTypeRequest(model);
    685         }
    686 
    687         /**
    688          * A helper class for building requests with custom {@link com.bumptech.glide.load.model.ModelLoader}s that
    689          * requires the user to specify a specific resource class that will be loaded.
    690          *
    691          */
    692         public final class GenericTypeRequest {
    693             private final A model;
    694             private final Class<A> modelClass;
    695             private final boolean providedModel;
    696 
    697             GenericTypeRequest(A model) {
    698                 providedModel = true;
    699                 this.model = model;
    700                 this.modelClass = getSafeClass(model);
    701             }
    702 
    703             GenericTypeRequest(Class<A> modelClass) {
    704                 providedModel = false;
    705                 this.model = null;
    706                 this.modelClass = modelClass;
    707             }
    708 
    709             /**
    710              * Sets the resource class that will be loaded.
    711              *
    712              * @param resourceClass The class of the resource that will be loaded.
    713              * @param <Z> The type of the resource that will be loaded.
    714              * @return This request builder.
    715              */
    716             public <Z> GenericTranscodeRequest<A, T, Z> as(Class<Z> resourceClass) {
    717                 GenericTranscodeRequest<A, T, Z> result =
    718                         optionsApplier.apply(new GenericTranscodeRequest<A, T, Z>(context, glide, modelClass,
    719                                 modelLoader, dataClass, resourceClass, requestTracker, lifecycle, optionsApplier));
    720                 if (providedModel) {
    721                     result.load(model);
    722                 }
    723                 return result;
    724             }
    725         }
    726     }
    727 
    728     class OptionsApplier {
    729 
    730         public <A, X extends GenericRequestBuilder<A, ?, ?, ?>> X apply(X builder) {
    731             if (options != null) {
    732                 options.apply(builder);
    733             }
    734             return builder;
    735         }
    736     }
    737 
    738     private static class RequestManagerConnectivityListener implements ConnectivityMonitor.ConnectivityListener {
    739         private final RequestTracker requestTracker;
    740 
    741         public RequestManagerConnectivityListener(RequestTracker requestTracker) {
    742             this.requestTracker = requestTracker;
    743         }
    744 
    745         @Override
    746         public void onConnectivityChanged(boolean isConnected) {
    747             if (isConnected) {
    748                 requestTracker.restartRequests();
    749             }
    750         }
    751     }
    752 }
    753