1 package com.bumptech.glide; 2 3 import android.content.Context; 4 import android.graphics.drawable.Drawable; 5 import android.view.animation.Animation; 6 import android.widget.ImageView; 7 8 import com.bumptech.glide.load.Encoder; 9 import com.bumptech.glide.load.Key; 10 import com.bumptech.glide.load.MultiTransformation; 11 import com.bumptech.glide.load.ResourceDecoder; 12 import com.bumptech.glide.load.ResourceEncoder; 13 import com.bumptech.glide.load.Transformation; 14 import com.bumptech.glide.load.engine.DiskCacheStrategy; 15 import com.bumptech.glide.load.resource.UnitTransformation; 16 import com.bumptech.glide.load.resource.transcode.ResourceTranscoder; 17 import com.bumptech.glide.manager.Lifecycle; 18 import com.bumptech.glide.manager.RequestTracker; 19 import com.bumptech.glide.provider.ChildLoadProvider; 20 import com.bumptech.glide.provider.LoadProvider; 21 import com.bumptech.glide.request.FutureTarget; 22 import com.bumptech.glide.request.GenericRequest; 23 import com.bumptech.glide.request.Request; 24 import com.bumptech.glide.request.RequestCoordinator; 25 import com.bumptech.glide.request.RequestFutureTarget; 26 import com.bumptech.glide.request.RequestListener; 27 import com.bumptech.glide.request.ThumbnailRequestCoordinator; 28 import com.bumptech.glide.request.animation.GlideAnimationFactory; 29 import com.bumptech.glide.request.animation.NoAnimation; 30 import com.bumptech.glide.request.animation.ViewAnimationFactory; 31 import com.bumptech.glide.request.animation.ViewPropertyAnimation; 32 import com.bumptech.glide.request.animation.ViewPropertyAnimationFactory; 33 import com.bumptech.glide.request.target.PreloadTarget; 34 import com.bumptech.glide.request.target.Target; 35 import com.bumptech.glide.signature.EmptySignature; 36 import com.bumptech.glide.util.Util; 37 38 import java.io.File; 39 40 /** 41 * A generic class that can handle setting options and staring loads for generic resource types. 42 * 43 * @paramThe type of model representing the resource. 44 * @param The data type that the resource {@link com.bumptech.glide.load.model.ModelLoader} will provide that 45 * can be decoded by the {@link com.bumptech.glide.load.ResourceDecoder}. 46 * @param The type of the resource that will be loaded. 47 * @param The type of resource the decoded resource will be transcoded to. 48 */ 49 public class GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> implements Cloneable { 50 protected final Class<ModelType> modelClass; 51 protected final Context context; 52 protected final Glide glide; 53 protected final Class<TranscodeType> transcodeClass; 54 protected final RequestTracker requestTracker; 55 protected final Lifecycle lifecycle; 56 private ChildLoadProvider<ModelType, DataType, ResourceType, TranscodeType> loadProvider; 57 58 private ModelType model; 59 private Key signature = EmptySignature.obtain(); 60 // model may occasionally be null, so to enforce that load() was called, set a boolean rather than relying on model 61 // not to be null. 62 private boolean isModelSet; 63 private int placeholderId; 64 private int errorId; 65 private RequestListener<? super ModelType, TranscodeType> requestListener; 66 private Float thumbSizeMultiplier; 67 private GenericRequestBuilder<?, ?, ?, TranscodeType> thumbnailRequestBuilder; 68 private Float sizeMultiplier = 1f; 69 private Drawable placeholderDrawable; 70 private Drawable errorPlaceholder; 71 private Priority priority = null; 72 private boolean isCacheable = true; 73 private GlideAnimationFactory<TranscodeType> animationFactory = NoAnimation.getFactory(); 74 private int overrideHeight = -1; 75 private int overrideWidth = -1; 76 private DiskCacheStrategy diskCacheStrategy = DiskCacheStrategy.RESULT; 77 private Transformation<ResourceType> transformation = UnitTransformation.get(); 78 private boolean isTransformationSet; 79 80 GenericRequestBuilder(LoadProvider<ModelType, DataType, ResourceType, TranscodeType> loadProvider, 81 Class<TranscodeType> transcodeClass, GenericRequestBuilder<ModelType, ?, ?, ?> other) { 82 this(other.context, other.modelClass, loadProvider, transcodeClass, other.glide, other.requestTracker, 83 other.lifecycle); 84 this.model = other.model; 85 this.isModelSet = other.isModelSet; 86 this.signature = other.signature; 87 this.diskCacheStrategy = other.diskCacheStrategy; 88 this.isCacheable = other.isCacheable; 89 } 90 91 GenericRequestBuilder(Context context, Class<ModelType> modelClass, 92 LoadProvider<ModelType, DataType, ResourceType, TranscodeType> loadProvider, 93 Class<TranscodeType> transcodeClass, Glide glide, RequestTracker requestTracker, Lifecycle lifecycle) { 94 this.context = context; 95 this.modelClass = modelClass; 96 this.transcodeClass = transcodeClass; 97 this.glide = glide; 98 this.requestTracker = requestTracker; 99 this.lifecycle = lifecycle; 100 this.loadProvider = loadProvider != null 101 ? new ChildLoadProvider<ModelType, DataType, ResourceType, TranscodeType>(loadProvider) : null; 102 103 if (context == null) { 104 throw new NullPointerException("Context can't be null"); 105 } 106 if (modelClass != null && loadProvider == null) { 107 throw new NullPointerException("LoadProvider must not be null"); 108 } 109 } 110 111 /** 112 * Loads and displays the resource retrieved by the given thumbnail request if it finishes before this request. 113 * Best used for loading thumbnail resources that are smaller and will be loaded more quickly than the full size 114 * resource. There are no guarantees about the order in which the requests will actually finish. However, if the 115 * thumb request completes after the full request, the thumb resource will never replace the full resource. 116 * 117 * @see #thumbnail(float) 118 * 119 * <p> 120 * Recursive calls to thumbnail are supported. 121 * </p> 122 * 123 * @param thumbnailRequest The request to use to load the thumbnail. 124 * @return This request builder. 125 */ 126 public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> thumbnail( 127 GenericRequestBuilder<?, ?, ?, TranscodeType> thumbnailRequest) { 128 this.thumbnailRequestBuilder = thumbnailRequest; 129 130 return this; 131 } 132 133 /** 134 * Loads a resource in an identical manner to this request except with the dimensions of the target multiplied 135 * by the given size multiplier. If the thumbnail load completes before the fullsize load, the thumbnail will 136 * be shown. If the thumbnail load completes afer the fullsize load, the thumbnail will not be shown. 137 * 138 * <p> 139 * Note - The thumbnail resource will be smaller than the size requested so the target (or {@link ImageView}) 140 * must be able to scale the thumbnail appropriately. See {@link android.widget.ImageView.ScaleType}. 141 * </p> 142 * 143 * <p> 144 * Almost all options will be copied from the original load, including the 145 * {@link com.bumptech.glide.load.model.ModelLoader}, {@link com.bumptech.glide.load.ResourceDecoder}, and 146 * {@link Transformation}s. However, {@link #placeholder(int)} and {@link #error(int)}, 147 * and {@link #listener(RequestListener)} will only be used on the fullsize load and will not be copied for 148 * the thumbnail load. 149 * </p> 150 * 151 * <p> 152 * Recursive calls to thumbnail are supported. 153 * </p> 154 * 155 * @param sizeMultiplier The multiplier to apply to the {@link Target}'s dimensions when loading the thumbnail. 156 * @return This request builder. 157 */ 158 public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> thumbnail( 159 float sizeMultiplier) { 160 if (sizeMultiplier < 0f || sizeMultiplier > 1f) { 161 throw new IllegalArgumentException("sizeMultiplier must be between 0 and 1"); 162 } 163 this.thumbSizeMultiplier = sizeMultiplier; 164 165 return this; 166 } 167 168 /** 169 * Applies a multiplier to the {@link Target}'s size before loading the resource. Useful for loading thumbnails 170 * or trying to avoid loading huge resources (particularly {@link android.graphics.Bitmap}s on devices with overly 171 * dense screens. 172 * 173 * @param sizeMultiplier The multiplier to apply to the {@link Target}'s dimensions when loading the resource. 174 * @return This request builder. 175 */ 176 public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> sizeMultiplier( 177 float sizeMultiplier) { 178 if (sizeMultiplier < 0f || sizeMultiplier > 1f) { 179 throw new IllegalArgumentException("sizeMultiplier must be between 0 and 1"); 180 } 181 this.sizeMultiplier = sizeMultiplier; 182 183 return this; 184 } 185 186 /** 187 * Sets the {@link com.bumptech.glide.load.ResourceDecoder} to use to load the resource from the original data. 188 * By default, this decoder will only be used if the final transformed resource is not in the disk cache. 189 * 190 * @see #cacheDecoder(com.bumptech.glide.load.ResourceDecoder) 191 * @see com.bumptech.glide.load.engine.DiskCacheStrategy 192 * 193 * @param decoder The {@link com.bumptech.glide.load.ResourceDecoder} to use to decode the resource. 194 * @return This request builder. 195 */ 196 public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> decoder( 197 ResourceDecoder<DataType, ResourceType> decoder) { 198 // loadProvider will be null if model is null, in which case we're not going to load anything so it's ok to 199 // ignore the decoder. 200 if (loadProvider != null) { 201 loadProvider.setSourceDecoder(decoder); 202 } 203 204 return this; 205 } 206 207 /** 208 * Sets the {@link com.bumptech.glide.load.ResourceDecoder} to use to load the resource from the disk cache. By 209 * default, this decoder will only be used if the final transformed resource is already in the disk cache. 210 * 211 * @see #decoder(com.bumptech.glide.load.ResourceDecoder) 212 * @see com.bumptech.glide.load.engine.DiskCacheStrategy 213 * 214 * @param cacheDecoder The decoder to use. 215 * @return This request builder. 216 */ 217 public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> cacheDecoder( 218 ResourceDecoder<File, ResourceType> cacheDecoder) { 219 // loadProvider will be null if model is null, in which case we're not going to load anything so it's ok to 220 // ignore the decoder. 221 if (loadProvider != null) { 222 loadProvider.setCacheDecoder(cacheDecoder); 223 } 224 225 return this; 226 } 227 228 /** 229 * Sets the source encoder to use to encode the data retrieved by this request directly into cache. The returned 230 * resource will then be decoded from the cached data. 231 * 232 * @see com.bumptech.glide.load.engine.DiskCacheStrategy 233 * 234 * @param sourceEncoder The encoder to use. 235 * @return This request builder. 236 */ 237 public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> sourceEncoder( 238 Encoder<DataType> sourceEncoder) { 239 if (loadProvider != null) { 240 loadProvider.setSourceEncoder(sourceEncoder); 241 } 242 243 return this; 244 } 245 246 /** 247 * Sets the {@link com.bumptech.glide.load.engine.DiskCacheStrategy} to use for this load. Defaults to 248 * {@link com.bumptech.glide.load.engine.DiskCacheStrategy#RESULT}. 249 * 250 * <p> 251 * For most applications {@link com.bumptech.glide.load.engine.DiskCacheStrategy#RESULT} is ideal. 252 * Applications that use the same resource multiple times in multiple sizes and are willing to trade off some 253 * speed and disk space in return for lower bandwidth usage may want to consider using 254 * {@link com.bumptech.glide.load.engine.DiskCacheStrategy#SOURCE} or 255 * {@link com.bumptech.glide.load.engine.DiskCacheStrategy#RESULT}. Any download only operations should 256 * typically use {@link com.bumptech.glide.load.engine.DiskCacheStrategy#SOURCE}. 257 * </p> 258 * 259 * @param strategy The strategy to use. 260 * @return This request builder. 261 */ 262 public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> diskCacheStrategy( 263 DiskCacheStrategy strategy) { 264 this.diskCacheStrategy = strategy; 265 266 return this; 267 } 268 269 /** 270 * Sets the {@link com.bumptech.glide.load.Encoder} to use to encode the original data directly to cache. Will only 271 * be used if the original data is not already in cache and if the 272 * {@link com.bumptech.glide.load.engine.DiskCacheStrategy} is set to 273 * {@link com.bumptech.glide.load.engine.DiskCacheStrategy#SOURCE} or 274 * {@link com.bumptech.glide.load.engine.DiskCacheStrategy#ALL}. 275 * 276 * @see #sourceEncoder(com.bumptech.glide.load.Encoder) 277 * @see com.bumptech.glide.load.engine.DiskCacheStrategy 278 * 279 * @param encoder The encoder to use. 280 * @return This request builder. 281 */ 282 public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> encoder( 283 ResourceEncoder<ResourceType> encoder) { 284 // loadProvider will be null if model is null, in which case we're not going to load anything so it's ok to 285 // ignore the encoder. 286 if (loadProvider != null) { 287 loadProvider.setEncoder(encoder); 288 } 289 290 return this; 291 } 292 293 /** 294 * Sets the priority for this load. 295 * 296 * @param priority A priority. 297 * @return This request builder. 298 */ 299 public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> priority( 300 Priority priority) { 301 this.priority = priority; 302 303 return this; 304 } 305 306 /** 307 * Transform resources with the given {@link Transformation}s. Replaces any existing transformation or 308 * transformations. 309 * 310 * @param transformations the transformations to apply in order. 311 * @return This request builder. 312 */ 313 public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> transform( 314 Transformation<ResourceType>... transformations) { 315 isTransformationSet = true; 316 if (transformations.length == 1) { 317 transformation = transformations[0]; 318 } else { 319 transformation = new MultiTransformation<ResourceType>(transformations); 320 } 321 322 return this; 323 } 324 325 /** 326 * Removes the current {@link com.bumptech.glide.load.Transformation}. 327 * 328 * @return This request builder. 329 */ 330 @SuppressWarnings("unchecked") 331 public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> dontTransform() { 332 Transformation<ResourceType> transformation = UnitTransformation.get(); 333 return transform(transformation); 334 } 335 336 /** 337 * Sets the {@link com.bumptech.glide.load.resource.transcode.ResourceTranscoder} to use for this load. 338 * 339 * @see com.bumptech.glide.load.resource.transcode.UnitTranscoder 340 * @see com.bumptech.glide.load.resource.transcode.GlideBitmapDrawableTranscoder 341 * @see com.bumptech.glide.load.resource.transcode.GifBitmapWrapperDrawableTranscoder 342 * 343 * @param transcoder The transcoder to use. 344 * @return This request builder. 345 */ 346 public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> transcoder( 347 ResourceTranscoder<ResourceType, TranscodeType> transcoder) { 348 if (loadProvider != null) { 349 loadProvider.setTranscoder(transcoder); 350 } 351 352 return this; 353 } 354 355 /** 356 * Removes any existing animation set on the builder. Will be overridden by subsequent calls that set an animation. 357 * @return This request builder. 358 */ 359 public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> dontAnimate() { 360 GlideAnimationFactory<TranscodeType> animation = NoAnimation.getFactory(); 361 return animate(animation); 362 } 363 364 /** 365 * Sets an animation to run on the wrapped target when an resource load finishes. Will only be run if the resource 366 * was loaded asynchronously (ie was not in the memory cache) 367 * 368 * @param animationId The resource id of the animation to run 369 * @return This request builder. 370 */ 371 public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> animate(int animationId) { 372 return animate(new ViewAnimationFactory<TranscodeType>(context, animationId)); 373 } 374 375 /** 376 * Sets an animation to run on the wrapped target when a resource load finishes. Will only be run if the resource 377 * was loaded asynchronously (ie was not in the memory cache) 378 * 379 * @see #animate(int) 380 * @see #animate(com.bumptech.glide.request.animation.ViewPropertyAnimation.Animator) 381 * 382 * @deprecated If this builder is used for multiple loads, using this method will result in multiple view's being 383 * asked to start an animation using a single {@link android.view.animation.Animation} object which results in 384 * views animating repeatedly. Use {@link #animate(int)} or 385 * {@link #animate(com.bumptech.glide.request.animation.ViewPropertyAnimation.Animator)}. Scheduled to be removed in 386 * Glide 4.0. 387 * @param animation The animation to run 388 * @return This request builder. 389 */ 390 @Deprecated 391 public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> animate(Animation animation) { 392 return animate(new ViewAnimationFactory<TranscodeType>(animation)); 393 } 394 395 /** 396 * Sets an animator to run a {@link android.view.ViewPropertyAnimator} on a view that the target may be wrapping 397 * when a resource load finishes. Will only be run if the load was loaded asynchronously (ie was not in the 398 * memory cache). 399 * 400 * @param animator The {@link com.bumptech.glide.request.animation.ViewPropertyAnimation.Animator} to run. 401 * @return This request builder. 402 */ 403 public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> animate( 404 ViewPropertyAnimation.Animator animator) { 405 return animate(new ViewPropertyAnimationFactory<TranscodeType>(animator)); 406 } 407 408 GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> animate( 409 GlideAnimationFactory<TranscodeType> animationFactory) { 410 if (animationFactory == null) { 411 throw new NullPointerException("Animation factory must not be null!"); 412 } 413 this.animationFactory = animationFactory; 414 415 return this; 416 } 417 418 /** 419 * Sets an Android resource id for a {@link android.graphics.drawable.Drawable} resourceto display while a resource 420 * is loading. 421 * 422 * @param resourceId The id of the resource to use as a placeholder 423 * @return This request builder. 424 */ 425 public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> placeholder( 426 int resourceId) { 427 this.placeholderId = resourceId; 428 429 return this; 430 } 431 432 /** 433 * Sets an {@link android.graphics.drawable.Drawable} to display while a resource is loading. 434 * 435 * @param drawable The drawable to display as a placeholder. 436 * @return This request builder. 437 */ 438 public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> placeholder( 439 Drawable drawable) { 440 this.placeholderDrawable = drawable; 441 442 return this; 443 } 444 445 /** 446 * Sets a resource to display if a load fails. 447 * 448 * @param resourceId The id of the resource to use as a placeholder. 449 * @return This request builder. 450 */ 451 public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> error( 452 int resourceId) { 453 this.errorId = resourceId; 454 455 return this; 456 } 457 458 /** 459 * Sets a {@link Drawable} to display if a load fails. 460 * 461 * @param drawable The drawable to display. 462 * @return This request builder. 463 */ 464 public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> error( 465 Drawable drawable) { 466 this.errorPlaceholder = drawable; 467 468 return this; 469 } 470 471 /** 472 * Sets a RequestBuilder listener to monitor the resource load. It's best to create a single instance of an 473 * exception handler per type of request (usually activity/fragment) rather than pass one in per request to 474 * avoid some redundant object allocation. 475 * 476 * @param requestListener The request listener to use. 477 * @return This request builder. 478 */ 479 public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> listener( 480 RequestListener<? super ModelType, TranscodeType> requestListener) { 481 this.requestListener = requestListener; 482 483 return this; 484 } 485 486 /** 487 * Allows the loaded resource to skip the memory cache. 488 * 489 * <p> 490 * Note - this is not a guarantee. If a request is already pending for this resource and that request is not 491 * also skipping the memory cache, the resource will be cached in memory. 492 * </p> 493 * 494 * @param skip True to allow the resource to skip the memory cache. 495 * @return This request builder. 496 */ 497 public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> skipMemoryCache(boolean skip) { 498 this.isCacheable = !skip; 499 500 return this; 501 } 502 503 /** 504 * Overrides the {@link Target}'s width and height with the given values. This is useful almost exclusively for 505 * thumbnails, and should only be used when you both need a very specific sized image and when it is impossible or 506 * impractical to return that size from {@link Target#getSize(com.bumptech.glide.request.target.SizeReadyCallback)}. 507 * 508 * @param width The width in pixels to use to load the resource. 509 * @param height The height in pixels to use to load the resource. 510 * @return This request builder. 511 */ 512 public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> override(int width, int height) { 513 if (width <= 0) { 514 throw new IllegalArgumentException("Width must be > 0"); 515 } 516 if (height <= 0) { 517 throw new IllegalArgumentException("Height must be > 0"); 518 } 519 this.overrideWidth = width; 520 this.overrideHeight = height; 521 522 return this; 523 } 524 525 /** 526 * Sets some additional data to be mixed in to the memory and disk cache keys allowing the caller more control over 527 * when cached data is invalidated. 528 * 529 * <p> 530 * Note - The signature does not replace the cache key, it is purely additive. 531 * </p> 532 * 533 * @see com.bumptech.glide.signature.StringSignature 534 * 535 * @param signature A unique non-null {@link com.bumptech.glide.load.Key} representing the current state of the 536 * model that will be mixed in to the cache key. 537 * @return This request builder. 538 */ 539 public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> signature(Key signature) { 540 if (signature == null) { 541 throw new NullPointerException("Signature must not be null"); 542 } 543 this.signature = signature; 544 return this; 545 } 546 547 /** 548 * Sets the specific model to load data for. 549 * 550 * <p> 551 * This method must be called at least once before {@link #into(com.bumptech.glide.request.target.Target)} is 552 * called. 553 * </p> 554 * 555 * @param model The model to load data for, or null. 556 * @return This request builder. 557 */ 558 public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> load(ModelType model) { 559 this.model = model; 560 isModelSet = true; 561 return this; 562 } 563 564 /** 565 * Returns a copy of this request builder with all of the options set so far on this builder. 566 * 567 * <p> 568 * This method returns a "deep" copy in that all non-immutable arguments are copied such that changes to one 569 * builder will not affect the other builder. However, in addition to immutable arguments, the current model 570 * is not copied copied so changes to the model will affect both builders. 571 * </p> 572 */ 573 @SuppressWarnings("unchecked") 574 @Override 575 public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> clone() { 576 try { 577 GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> clone = 578 (GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType>) super.clone(); 579 clone.loadProvider = loadProvider != null ? loadProvider.clone() : null; 580 return clone; 581 } catch (CloneNotSupportedException e) { 582 throw new RuntimeException(e); 583 } 584 } 585 586 /** 587 * Set the target the resource will be loaded into. 588 * 589 * @see Glide#clear(com.bumptech.glide.request.target.Target) 590 * 591 * @param target The target to load the resource into. 592 * @return The given target. 593 */ 594 public <Y extends Target<TranscodeType>> Y into(Y target) { 595 Util.assertMainThread(); 596 if (target == null) { 597 throw new IllegalArgumentException("You must pass in a non null Target"); 598 } 599 if (!isModelSet) { 600 throw new IllegalArgumentException("You must first set a model (try #load())"); 601 } 602 603 Request previous = target.getRequest(); 604 605 if (previous != null) { 606 previous.clear(); 607 requestTracker.removeRequest(previous); 608 previous.recycle(); 609 } 610 611 Request request = buildRequest(target); 612 target.setRequest(request); 613 lifecycle.addListener(target); 614 requestTracker.runRequest(request); 615 616 return target; 617 } 618 619 /** 620 * Sets the {@link ImageView} the resource will be loaded into, cancels any existing loads into the view, and frees 621 * any resources Glide may have previously loaded into the view so they may be reused. 622 * 623 * @see Glide#clear(android.view.View) 624 * 625 * @param view The view to cancel previous loads for and load the new resource into. 626 * @return The {@link com.bumptech.glide.request.target.Target} used to wrap the given {@link ImageView}. 627 */ 628 public Target<TranscodeType> into(ImageView view) { 629 Util.assertMainThread(); 630 if (view == null) { 631 throw new IllegalArgumentException("You must pass in a non null View"); 632 } 633 634 if (!isTransformationSet && view.getScaleType() != null) { 635 switch (view.getScaleType()) { 636 case CENTER_CROP: 637 applyCenterCrop(); 638 break; 639 case FIT_CENTER: 640 case FIT_START: 641 case FIT_END: 642 applyFitCenter(); 643 break; 644 //$CASES-OMITTED$ 645 default: 646 // silently ignore 647 break; 648 } 649 } 650 651 return into(glide.buildImageViewTarget(view, transcodeClass)); 652 } 653 654 /** 655 * Returns a future that can be used to do a blocking get on a background thread. 656 * 657 * @param width The desired width in pixels (note this will be overriden by {@link #override(int, int)} if 658 * previously called). 659 * @param height The desired height in pixels (note this will be overriden by {@link #override(int, int)}} 660 * if previously called). 661 * 662 * @see Glide#clear(com.bumptech.glide.request.FutureTarget) 663 * 664 * @return An {@link com.bumptech.glide.request.FutureTarget} that can be used to obtain the 665 * resource in a blocking manner. 666 */ 667 public FutureTarget<TranscodeType> into(int width, int height) { 668 final RequestFutureTarget<ModelType, TranscodeType> target = 669 new RequestFutureTarget<ModelType, TranscodeType>(glide.getMainHandler(), width, height); 670 671 // TODO: Currently all loads must be started on the main thread... 672 glide.getMainHandler().post(new Runnable() { 673 @Override 674 public void run() { 675 if (!target.isCancelled()) { 676 into(target); 677 } 678 } 679 }); 680 681 return target; 682 } 683 684 /** 685 * Preloads the resource into the cache using the given width and height. 686 * 687 * <p> 688 * Pre-loading is useful for making sure that resources you are going to to want in the near future are 689 * available quickly. 690 * </p> 691 * 692 * @see com.bumptech.glide.ListPreloader 693 */ 694 public Target<TranscodeType> preload(int width, int height) { 695 final PreloadTarget<TranscodeType> target = PreloadTarget.obtain(width, height); 696 return into(target); 697 } 698 699 void applyCenterCrop() { 700 // To be implemented by subclasses when possible. 701 } 702 703 void applyFitCenter() { 704 // To be implemented by subclasses when possible. 705 } 706 707 private Priority getThumbnailPriority() { 708 final Priority result; 709 if (priority == Priority.LOW) { 710 result = Priority.NORMAL; 711 } else if (priority == Priority.NORMAL) { 712 result = Priority.HIGH; 713 } else { 714 result = Priority.IMMEDIATE; 715 } 716 return result; 717 } 718 719 private Request buildRequest(Target<TranscodeType> target) { 720 if (priority == null) { 721 priority = Priority.NORMAL; 722 } 723 return buildRequestRecursive(target, null); 724 } 725 726 private Request buildRequestRecursive(Target<TranscodeType> target, ThumbnailRequestCoordinator parentCoordinator) { 727 if (thumbnailRequestBuilder != null) { 728 // Recursive case: contains a potentially recursive thumbnail request builder. 729 if (thumbnailRequestBuilder.animationFactory.equals(NoAnimation.getFactory())) { 730 thumbnailRequestBuilder.animationFactory = animationFactory; 731 } 732 733 if (thumbnailRequestBuilder.priority == null) { 734 thumbnailRequestBuilder.priority = getThumbnailPriority(); 735 } 736 737 ThumbnailRequestCoordinator coordinator = new ThumbnailRequestCoordinator(parentCoordinator); 738 Request fullRequest = obtainRequest(target, sizeMultiplier, priority, coordinator); 739 // Recursively generate thumbnail requests. 740 Request thumbRequest = thumbnailRequestBuilder.buildRequestRecursive(target, coordinator); 741 coordinator.setRequests(fullRequest, thumbRequest); 742 return coordinator; 743 } else if (thumbSizeMultiplier != null) { 744 // Base case: thumbnail multiplier generates a thumbnail request, but cannot recurse. 745 ThumbnailRequestCoordinator coordinator = new ThumbnailRequestCoordinator(parentCoordinator); 746 Request fullRequest = obtainRequest(target, sizeMultiplier, priority, coordinator); 747 Request thumbnailRequest = obtainRequest(target, thumbSizeMultiplier, getThumbnailPriority(), coordinator); 748 coordinator.setRequests(fullRequest, thumbnailRequest); 749 return coordinator; 750 } else { 751 // Base case: no thumbnail. 752 return obtainRequest(target, sizeMultiplier, priority, parentCoordinator); 753 } 754 } 755 756 private Request obtainRequest(Target<TranscodeType> target, float sizeMultiplier, Priority priority, 757 RequestCoordinator requestCoordinator) { 758 return GenericRequest.obtain( 759 loadProvider, 760 model, 761 signature, 762 context, 763 priority, 764 target, 765 sizeMultiplier, 766 placeholderDrawable, 767 placeholderId, 768 errorPlaceholder, 769 errorId, 770 requestListener, 771 requestCoordinator, 772 glide.getEngine(), 773 transformation, 774 transcodeClass, 775 isCacheable, 776 animationFactory, 777 overrideWidth, 778 overrideHeight, 779 diskCacheStrategy); 780 } 781 } 782