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