About

Targets in Glide act as mediators between requests and requestors. Targets are responsible for displaying placeholders, loaded resources, and determining the appropriate dimensions for each request. The most frequently used Targets are ImageViewTargets that display placeholders, Drawables, and Bitmaps using ImageView. Users can also implement their own Targets, or subclass any of the available base classes.

Specifying Targets

The into(Target) method is used not only to start each request, but also to specify the Target that will receive the results of the request:

Target<Drawable> target = 
  Glide.with(fragment)
    .load(url)
    .into(new Target<Drawable>() {
      ...
    });

Glide provides a helper method for into(ImageView) that takes an ImageView and wraps it in a ImageViewTarget appropriate for the requested resource type for you:

Target<Drawable> target = 
  Glide.with(fragment)
    .load(url)
    .into(imageView);

Cancellation and re-use

Note that both into(Target) and into(ImageView) return a Target instance. If you re-use this Target to start a new load in the future, any previously started requests will be cancelled and their resources released:

Target<Drawable> target = 
  Glide.with(fragment)
    .load(url)
    .into(new Target<Drawable>() {
      ...
    });
... 
// Some time in the future:
Glide.with(fragment)
  .load(newUrl)
  .into(target);

You can also use the returned Target to clear() out any pending loads and release any associated resources without starting a new load:

Target<Drawable> target = 
  Glide.with(fragment)
    .load(url)
    .into(new Target<Drawable>() {
      ...
    });
... 
// Some time in the future:
Glide.with(fragment).clear(target);

Glide’s ViewTarget subclasses store information about each request in the View using the Android Framework’s getTag() and setTag() methods, so if you’re using a ViewTarget subclass or loading into an ImageView, you can re-use or clear the View directly:

Glide.with(fragment)
  .load(url)
  .into(imageView);

// Some time in the future:
Glide.with(fragment).clear(imageView);

// Or:
Glide.with(fragment)
  .load(newUrl)
  .into(imageView);

In addition, for ViewTargets only, you can pass in a new instance to each load or clear call and allow Glide to retrieve information about previous loads from the Views tags:

Glide.with(fragment)
  .load(url)
  .into(new DrawableImageViewTarget(imageView));

// Some time in the future:
Glide.with(fragment)
  .load(newUrl)
  .into(new DrawableImageViewTarget(imageView));

This will not work unless your Target extends ViewTarget or implements setRequest() and getRequest() in a way that allows you to retrieve previous requests in new Target instances.

Clear

It’s always good practice to clear() out any Target you create when you’re done with any resource (Bitmap, Drawable etc) that you’ve loaded into it. You should use clear() even if you think your request has finished to let Glide re-use any resources (Bitmaps in particular) used by the load. Failing to clear() a Target can waste CPU and memory, block more important loads, or even result in the wrong image appearing if you have two Targets that display images in the same surface (View, Notification, RPC etc). Clear is especially critical for Targets like SimpleTarget that can’t keep track of previous requests from other SimpleTarget instances.

Sizes and dimensions

By default, Glide uses the size provided by Targets via the getSize() method as the target size for the request. Doing so allows Glide to choose an appropriate url, downsample, crop, and Transform size appropriate images to minimize memory usage, and make sure loads are as fast as possible.

View Targets

ViewTargets implement getSize() by inspecting the attributes of the View and/or using an OnPreDrawListener to measure the View immediately before it is rendered. As a result, Glide can automatically resize most images to match the View they will be displayed in. Loading smaller images lets Glide load them faster (after they’ve been disk cached), use less memory, and increases the hit rate of Glide’s BitmapPool if the View sizes are consistent.

The logic ViewTarget uses is as follows:

  1. If the View’s layout parameter dimensions are > 0 and > padding, use the layout parameters
  2. If the View dimensions are > 0 and > padding, use the view dimensions
  3. If the View layout parameters are wrap_content and at least one layout pass has occurred, log a warning suggesting to use Target.SIZE_ORIGINAL or some other fixed size via override() and use the screen dimensions.
  4. Otherwise (layout parameters are match_parent, 0, or wrap_content and no layout pass has occurred), wait for a layout pass, then go back to step 1.

Sometimes when using RecyclerView, a View may be re-used and retain the size from a previous position that will be changed for the current position. To handle those cases, you can create a new [ViewTarget and pass in true for waitForLayout]:

@Override
public void onBindViewHolder(VH holder, int position) {
  Glide.with(fragment)
    .load(urls.get(position))
    .into(new DrawableImageViewTarget(holder.imageView, /*waitForLayout=*/ true));
Performant View Sizes

In general Glide provides the fastest and most predictable results when explicit dp sizes are set on Views it loads into. However when that’s not possible, Glide also provides robust support for layout weights, match_parent and other relative sizes using OnPreDrawListeners. Finally, if nothing else will work, Glide should provide reasonable behavior for wrap_content as well.

Alternatives

If in any case Glide seems to get View sizes wrong, you can always manually override the size, either by extending ViewTarget and implementing your own logic, or by using the override() method in RequestOptions.

Custom Targets

If you’re using a custom Target and you’re not loading into a View that would allow you to subclass ViewTarget, you’ll need to implement the getSize() method.

The simplest possible way to implement getSize() is to simply call the provided callback immediately:

@Override
public void getSize(SizeReadyCallback cb) {
  cb.onSizeReady(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL);
}

Using Target.SIZE_ORIGINAL can be very inefficient or cause OOMs if your image sizes are large enough. As an alternative, You can also pass in a size to your Target’s constructor and provide those dimensions to the callback:

public class CustomTarget<T> implements Target<T> {
  private final int width;
  private final int height;
 
  public CustomTarget(int width, int height) {
    this.width = width;
    this.height = height;
  }

  ...

  @Override
  public void getSize(SizeReadyCallback cb) {
    cb.onSizeReady(width, height);
  }
}

Passing in a specific set of dimensions works well when you’re using consistent sizes in your application or when you know exactly what size you need. If you don’t know what size you need but could find out asynchronously, you can retain any callbacks you’re given in getSize() in a List<SizeReadyCallBack>, run some asynchronous process and then notify the callbacks you’ve retained when you figure out what the size should be.

Be sure to also implement removeCallback if you retain callbacks to avoid memory leaks.

For an example see the logic in Glide’s ViewTarget.

Animated Resources and custom Targets.

If you’re just loading the GifDrawable, or really any resource type, into a View you should always use into(ImageView) when possible. In addition to graceful handling or new requests, most of Glide’s ViewTarget implementations will already take care of starting animated Drawables for you. If you absolutely must have a custom Target be sure to either or extend ViewTarget or rigorously clear the Target returned from into(Target) before starting new loads or when you’re done displaying the resource you loaded.

If you’re not loading into a View, using ViewTarget directly or using a custom Target like SimpleTarget and you’re loading an animated resource like GifDrawable, you need to make sure to start the animated Drawable in onResourceReady:

Glide.with(fragment)
  .asGif()
  .load(url)
  .into(new SimpleTarget<>() {
    @Override
    public void onResourceReady(GifDrawable resource, Transition<GifDrawable> transition) {
      resource.start();
      // Set the resource wherever you need to use it.
    }
  });

If you’re loading either a Bitmap or a GifDrawable, you can check to see if the Drawable implements Animatable:

Glide.with(fragment)
  .load(url)
  .into(new SimpleTarget<>() {
    @Override
    public void onResourceReady(Drawable resource, Transition<GifDrawable> transition) {
      if (resource instanceof Animatable) {
        resource.start();
      }
      // Set the resource wherever you need to use it.
    }
  });