Setup

For Glide’s configuration to work properly, libraries and applications need to perform a certain set of steps. Note that libraries that do not wish to register additional components are not required to do this.

Applications

Applications must:

  1. Add exactly one AppGlideModule implementation
  2. Optionally add one or more LibraryGlideModule implementations.
  3. Add the @GlideModule annotation to the AppGlideModule implementation and all LibraryGlideModule implementations.
  4. Add a dependency on Glide’s annotation processor.
  5. Add a proguard keep for AppGlideModules.

An example AppGlideModule from Glide’s Flickr sample app looks like this:

@GlideModule
public class FlickrGlideModule extends AppGlideModule {
  @Override
  public void registerComponents(Context context, Glide glide, Registry registry) {
    registry.append(Photo.class, InputStream.class, new FlickrModelLoader.Factory());
  }
}

Including Glide’s annotation processor requires dependencies on Glide’s annotations and the annotation processor:

compile 'com.github.bumptech.glide:annotations:4.8.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.8.0'

Finally, you should keep AppGlideModule implementations in your proguard.cfg:

-keep public class * extends com.bumptech.glide.module.AppGlideModule
-keep class com.bumptech.glide.GeneratedAppGlideModuleImpl

Libraries

Libraries that do not register custom components do not need to perform any configuration steps and can skip the sections on this page entirely.

Libraries that do need to register a custom component, like a ModelLoader, can do the following:

  1. Add one or more LibraryGlideModule implementations that register the new components.
  2. Add the @GlideModule annotation to every LibraryGlideModule implementation
  3. Add a dependency on Glide’s annotation processor.

An example LibraryGlideModule from Glide’s OkHttp integration library looks like this:

@GlideModule
public final class OkHttpLibraryGlideModule extends LibraryGlideModule {
  @Override
  public void registerComponents(Context context, Glide glide, Registry registry) {
    registry.replace(GlideUrl.class, InputStream.class, new OkHttpUrlLoader.Factory());
  }
}

Using the @GlideModule annotation requires a dependency on Glide’s annotations:

compile 'com.github.bumptech.glide:annotations:4.8.0'
Avoid AppGlideModule in libraries

Libraries must not include AppGlideModule implementations. Doing so will prevent any applications that depend on the library from managing their dependencies or configuring options like Glide’s cache sizes and locations.

In addition, if two libraries include AppGlideModules, applications will be unable to compile if they depend on both and will be forced to pick one or other other.

This does mean that libraries won’t be able to use Glide’s generated API, but loads with RequestOptions will still work just fine (see the options page for examples).

Application Options

Glide allows applications to use AppGlideModule implementations to completely control Glide’s memory and disk cache usage. Glide tries to provide reasonable defaults for most applications, but for some applications, it will be necessary to customize these values. Be sure to measure the results of any changes to avoid performance regressions.

Memory cache

By default, Glide uses LruResourceCache, a default implementation of the MemoryCache interface that uses a fixed amount of memory with LRU eviction. The size of the LruResourceCache is determined by Glide’s MemorySizeCalculator class, which looks at the device memory class, whether or not the device is low ram and the screen resolution.

Applications can customize the MemoryCache size in their AppGlideModule with the applyOptions(Context, GlideBuilder) method by configuring MemorySizeCalculator:

@GlideModule
public class YourAppGlideModule extends AppGlideModule {
  @Override
  public void applyOptions(Context context, GlideBuilder builder) {
    MemorySizeCalculator calculator = new MemorySizeCalculator.Builder(context)
        .setMemoryCacheScreens(2)
        .build();
    builder.setMemoryCache(new LruResourceCache(calculator.getMemoryCacheSize()));
  }
}

Applications can also directly override the cache size:

@GlideModule
public class YourAppGlideModule extends AppGlideModule {
  @Override
  public void applyOptions(Context context, GlideBuilder builder) {
    int memoryCacheSizeBytes = 1024 * 1024 * 20; // 20mb
    builder.setMemoryCache(new LruResourceCache(memoryCacheSizeBytes));
  }
}

Applications can even provide their own implementation of MemoryCache:

@GlideModule
public class YourAppGlideModule extends AppGlideModule {
  @Override
  public void applyOptions(Context context, GlideBuilder builder) {
    builder.setMemoryCache(new YourAppMemoryCacheImpl());
  }
}

Bitmap pool

Glide uses LruBitmapPool as the default BitmapPool. LruBitmapPool is a fixed size in memory BitmapPool that uses LRU eviction. The default size is based on the screen size and density of the device in question as well as the memory class and the return value of isLowRamDevice. The specific calculations are done by Glide’s MemorySizeCalculator, similar to the way sizes are determined for Glide’s MemoryCache.

Applications can customize the BitmapPool size in their AppGlideModule with the applyOptions(Context, GlideBuilder) method by configuring MemorySizeCalculator:

@GlideModule
public class YourAppGlideModule extends AppGlideModule {
  @Override
  public void applyOptions(Context context, GlideBuilder builder) {
    MemorySizeCalculator calculator = new MemorySizeCalculator.Builder(context)
        .setBitmapPoolScreens(3)
        .build();
    builder.setBitmapPool(new LruBitmapPool(calculator.getBitmapPoolSize()));
  }
}

Applications can also directly override the pool size:

@GlideModule
public class YourAppGlideModule extends AppGlideModule {
  @Override
  public void applyOptions(Context context, GlideBuilder builder) {
    int bitmapPoolSizeBytes = 1024 * 1024 * 30; // 30mb
    builder.setBitmapPool(new LruBitmapPool(bitmapPoolSizeBytes));
  }
}

Applications can even provide their own implementation of BitmapPool:

@GlideModule
public class YourAppGlideModule extends AppGlideModule {
  @Override
  public void applyOptions(Context context, GlideBuilder builder) {
    builder.setBitmapPool(new YourAppBitmapPoolImpl());
  }
}

Disk Cache

Glide uses DiskLruCacheWrapper as the default DiskCache. DiskLruCacheWrapper is a fixed size disk cache with LRU eviction. The default disk cache size is 250 MB and is placed in a specific directory in the Application’s cache folder.

Applications can change the location to external storage if the media they display is public (obtained from websites without authentication, search engines etc):

@GlideModule
public class YourAppGlideModule extends AppGlideModule {
  @Override
  public void applyOptions(Context context, GlideBuilder builder) {
    builder.setDiskCache(new ExternalCacheDiskCacheFactory(context));
  }
}

Applications can change the size of the disk, for either the internal or external disk caches:

@GlideModule
public class YourAppGlideModule extends AppGlideModule {
  @Override
  public void applyOptions(Context context, GlideBuilder builder) {
    int diskCacheSizeBytes = 1024 * 1024 * 100; // 100 MB
    builder.setDiskCache(new InternalCacheDiskCacheFactory(context, diskCacheSizeBytes));
  }
}

Applications can change the name of the folder the cache is placed in within external or internal storage:

@GlideModule
public class YourAppGlideModule extends AppGlideModule {
  @Override
  public void applyOptions(Context context, GlideBuilder builder) {
    int diskCacheSizeBytes = 1024 * 1024 * 100; // 100 MB
    builder.setDiskCache(
        new InternalCacheDiskCacheFactory(context, "cacheFolderName", diskCacheSizeBytes));
  }
}

Applications can also choose to implement the DiskCache interface themselves and provide their own DiskCache.Factory to produce it. Glide uses a Factory interface to open DiskCaches on background threads so that the caches can do I/O like checking the existence of their target directory without causing a StrictMode violation.

@GlideModule
public class YourAppGlideModule extends AppGlideModule {
  @Override
  public void applyOptions(Context context, GlideBuilder builder) {
    builder.setDiskCache(new DiskCache.Factory() {
        @Override
        public DiskCache build() {
          return new YourAppCustomDiskCache();
        }
    });
  }
}

Default Request Options

Although RequestOptions are typically specified per request, you can also apply a default set of RequestOptions that will be applied to every load you start in your application by using an AppGlideModule:

@GlideModule
public class YourAppGlideModule extends AppGlideModule {
  @Override
  public void applyOptions(Context context, GlideBuilder builder) {
    builder.setDefaultRequestOptions(
        new RequestOptions()
          .format(DecodeFormat.RGB_565)
          .disallowHardwareBitmaps());
  }
}

Options applied with setDefaultRequestOptions in GlideBuilder are applied as soon as you create a new request. As a result, options applied to any individual request will override any conflicting options that are set in the GlideBuilder.

RequestManagers similarly allow you to set default RequestOptions for all loads started with that particular RequestManager. Since each Activity and Fragment gets its own RequestManager, you can use RequestManager's applyDefaultRequestOptions method to set default RequestOptions that apply only to a particular Activity or Fragment:

Glide.with(fragment)
  .applyDefaultRequestOptions(
      new RequestOptions()
          .format(DecodeFormat.RGB_565)
          .disallowHardwareBitmaps());

RequestManager also has a setDefaultRequestOptions that will completely replace any default RequestOptions previously set either via the GlideBuilder in an AppGlideModule or via the RequestManager. Use caution with setDefaultRequestOptions because it’s easy to accidentally override important defaults you’ve set elsewhere. Typically applyDefaultRequestOptions is safer and more intuitive to use.

UncaughtThrowableStrategy

When loading a bitmap, if an exception happens (e.g. OutOfMemoryException), Glide will use a GlideExecutor.UncaughtThrowableStrategy. The default strategy is to log the exception in the device logcat. The strategy is customizable since Glide 4.2.0. It can be passed to a disk executor and/or a resize executor:

@GlideModule
public class YourAppGlideModule extends AppGlideModule {
  @Override
  public void applyOptions(Context context, GlideBuilder builder) {
    final UncaughtThrowableStrategy myUncaughtThrowableStrategy = new ...
    builder.setDiskCacheExecutor(newDiskCacheExecutor(myUncaughtThrowableStrategy));
    builder.setResizeExecutor(newSourceExecutor(myUncaughtThrowableStrategy));
  }
}

Log level

For a subset of well formatted logs, including lines logged when a request fails, you can use setLogLevel with one of the values from Android’s Log class. Generally speaking log.VERBOSE will make logs noisier and Log.ERROR will make logs quieter, but see the javadoc for details.

@GlideModule
public class YourAppGlideModule extends AppGlideModule {
  @Override
  public void applyOptions(Context context, GlideBuilder builder) {
    builder.setLogLevel(Log.DEBUG);
  }
}

Registering Components

Both Applications and Libraries can register a number of components that extend Glides functionality. Available components include:

  1. ModelLoaders to load custom Models (Urls, Uris, arbitrary POJOs) and Data (InputStreams, FileDescriptors).
  2. ResourceDecoders to decode new Resources (Drawables, Bitmaps) or new types of Data (InputStreams, FileDescriptors).
  3. Encoders to write Data (InputStreams, FileDescriptors) to Glide’s disk cache.
  4. ResourceTranscoders to convert Resources (BitmapResource) into other types of Resources (DrawableResource).
  5. ResourceEncoders to write Resources (BitmapResource, DrawableResource) to Glide’s disk cache.

Components are registered using the Registry class in the registerComponents() method of AppGlideModules and LibraryGlideModules:

@GlideModule
public class YourAppGlideModule extends AppGlideModule {
  @Override
  public void registerComponents(Context context, Glide glide, Registry registry) {
    registry.append(...);
  }
}

or:

@GlideModule
public class YourLibraryGlideModule extends LibraryGlideModule {
  @Override
  public void registerComponents(Context context, Glide glide, Registry registry) {
    registry.append(...);
  }
}

Any number of components can registered in a single GlideModule. Certain types, including ModelLoaders and ResourceDecoders can have multiple implementations with the same type arguments.

Anatomy of a load

The set of registered components, including both those registered by default in Glide and those registered in Modules are used to define a set of load paths. Each load path is a step by step progression from the the Model provided to load() to the Resource type specified by as(). A load path consists (roughly) of the following steps:

  1. Model -> Data (handled by ModelLoaders)
  2. Data -> Resource (handled by ResourceDecoders)
  3. Resource -> Transcoded Resource (optional, handled by ResourceTranscoders).

Encoders can write Data to Glide’s disk cache cache before step 2. ResourceEncoders can write Resource’s to Glide’s disk cache before step 3.

When a request is started, Glide will attempt all available paths from the Model to the requested Resource type. A request will succeed if any load path succeeds. A request will fail only if all available load paths fail.

Ordering Components

The prepend(), append(), and replace() methods in Registry can be used to set the order in which Glide will attempt each ModelLoader and ResourceDecoder. Ordering components allows you to register components that handle specific subsets of models or data (IE only certain types of Uris, or only certain image formats) while also having an appended catch-all component to handle the rest.

prepend()

To handle subsets of existing data where you do want to fall back to Glide’s default behavior if your ModelLoader or ResourceDecoder fails, using prepend(). prepend() will make sure that your ModelLoader or ResourceDecoder is called before all other previously registered components and can run first. If your ModelLoader or ResourceDecoder returns false from its handles() method or fails, all other ModelLoaders or ResourceDecoders will be called in the order they’re registered, one at a time, providing a fallback.

append()

To handle new types of data or to add a fallback to Glide’s default behavior, using append(). append() will make sure that your ModelLoader or ResourceDecoder is called only after Glide’s defaults are attempted. If you’re trying to handle subtypes that Glide’s default components handle (like a specific Uri authority or subclass), you may need to use prepend() to make sure Glide’s default component doesn’t load the resource before your custom component.

replace()

To completely replace Glide’s default behavior and ensure that it doesn’t run, use replace(). replace() removes all ModelLoaders that handle the given model and data classes and then adds your ModelLoader instead. replace() is useful in particular for swapping out Glide’s networking logic with a library like OkHttp or Volley, where you want to make sure that only OkHttp or Volley are used.

Adding a ModelLoader

For example, to add a ModelLoader that can obtain an InputStream for a new custom Model object:

@GlideModule
public class YourAppGlideModule extends AppGlideModule {
  @Override
  public void registerComponents(Context context, Glide glide, Registry registry) {
    registry.append(Photo.class, InputStream.class, new CustomModelLoader.Factory());
  }
}

append() can be used safely here because Photo.class is a custom model object specific to your application, so you know that there is no default behavior in Glide that you need to replace.

In contrast, to add handling for a new type of String url in a BaseGlideUrlLoader, you should use prepend() so that your ModelLoader gets to run before Glide’s default ModelLoaders for Strings:

@GlideModule
public class YourAppGlideModule extends AppGlideModule {
  @Override
  public void registerComponents(Context context, Glide glide, Registry registry) {
    registry.prepend(String.class, InputStream.class, new CustomUrlModelLoader.Factory());
  }
}

Finally to completely remove and replace Glide’s default handling of a certain type, like a networking library, you should use replace():

@GlideModule
public class YourAppGlideModule extends AppGlideModule {
  @Override
  public void registerComponents(Context context, Glide glide, Registry registry) {
    registry.replace(GlideUrl.class, InputStream.class, new OkHttpUrlLoader.Factory());
  }
}

Module classes and annotations.

Glide v4 relies on two classes, AppGlideModule and LibraryGlideModule, to configure the Glide singleton. Both classes are allowed to register additional components, like ModelLoaders, ResourceDecoders etc. Only the AppGlideModules are allowed to configure application specific settings, like cache implementations and sizes.

AppGlideModule

All applications must add a AppGlideModule implementation, even if the Application is not changing any additional settings or implementing any methods in AppGlideModule. The AppGlideModule implementation acts as a signal that allows Glide’s annotation processor to generate a single combined class with with all discovered LibraryGlideModules.

There can be only one AppGlideModule implementation in a given application (having more than one produce errors at compile time). As a result, libraries must never provide a AppGlideModule implementation.

@GlideModule

In order for Glide to properly discover AppGlideModule and LibraryGlideModule implementations, all implementations of both classes must be annotated with the @GlideModule annotation. The annotation will allow Glide’s annotation processor to discover all implementations at compile time.

Annotation Processor

In addition, to enable discovery of the AppGlideModule and LibraryGlideModules all libraries and applications must also include a dependency on Glide’s annotation processor.

Conflicts

Applications may depend on multiple libraries, each of which may contain one or more LibraryGlideModules. In rare cases, these LibraryGlideModules may define conflicting options or otherwise include behavior the application would like to avoid. Applications can resolve these conflicts or avoid unwanted dependencies by adding an @Excludes annotation to their AppGlideModule.

For example if you depend on a library that has a LibraryGlideModule that you’d like to avoid, say com.example.unwanted.GlideModule:

@Excludes(com.example.unwanted.GlideModule.class)
@GlideModule
public final class MyAppGlideModule extends AppGlideModule { }

You can also excludes multiple modules:

@Excludes({com.example.unwanted.GlideModule.class, com.example.conflicing.GlideModule.class})
@GlideModule
public final class MyAppGlideModule extends AppGlideModule { }

@Excludes can be used to exclude both LibraryGlideModules and legacy, deprecated GlideModule implementations if you’re still in the process of migrating from Glide v3.

Manifest Parsing

To maintain backward compatibility with Glide v3’s GlideModules, Glide still parses AndroidManifest.xml files from both the application and any included libraries and will include any legacy GlideModules listed in the manifest. Although this functionality will be removed in a future version, we’ve retained the behavior for now to ease the transition.

If you’ve already migrated to the Glide v4 AppGlideModule and LibraryGlideModule, you can disable manifest parsing entirely. Doing so can improve the initial startup time of Glide and avoid some potential problems with trying to parse metadata. To disable manifest parsing, override the isManifestParsingEnabled() method in your AppGlideModule implementation:

@GlideModule
public final class MyAppGlideModule extends AppGlideModule {
  @Override
  public boolean isManifestParsingEnabled() {
    return false;
  }
}