Glide Module Example: Customize Caching

In the last tutorial, we went through the process of setting up our own Glide module to use a custom HTTP client, which accepts self-signed HTTPS certificates. This week, we stay on a low level and look at options to customize the caching components of Glide.

Glide Series Overview

Customize Memory Cache

Hopefully, you've read the caching basics and Glide modules posts. Otherwise some of the following code might look like magic to you. If you're ready to go, read on.

Alright, since we're customizing Glide, we'll need to create a new Glide module. As you've seen in the previous tutorials, the applyOptions method gives us access to the GlideBuilder object. The GlideBuilder offers us several methods to customize Glide's caching. First, let's look at the memory cache.

The memory cache keeps the images in the device's RAM. There is no IO action going on and thus it's very fast. The flip side is that the size of the RAM is quite limited. Finding the right balance of keeping a large memory cache (space for many images) versus a small memory cache (minimize our app's hunger for resources) is not easy. Glide internally uses the MemorySizeCalculator class to determine the size of the memory cache and the bitmap pool. The bitmap pool keeps the images allocated in your app's heap. The correct size of the bitmap pool is essential as well, since it avoids too many re-allocations of images and thus makes the garbage collector's life easier.

Luckily, you've access to Glide's MemorySizeCalculator class and the default calculation:

Glide 4.x

MemorySizeCalculator calculator = new MemorySizeCalculator.Builder(context).build();  
int defaultMemoryCacheSize = calculator.getMemoryCacheSize();  
int defaultBitmapPoolSize = calculator.getBitmapPoolSize();  

Glide 3.x

MemorySizeCalculator calculator = new MemorySizeCalculator(context);  
int defaultMemoryCacheSize = calculator.getMemoryCacheSize();  
int defaultBitmapPoolSize = calculator.getBitmapPoolSize();  

The code above is useful if we want to use the default values as baseline and adjust it from there. For example, if you think your app needs 20% larger caches than Glide's default values, calculate them using our variables above:

int customMemoryCacheSize = (int) (1.2 * defaultMemoryCacheSize);  
int customBitmapPoolSize = (int) (1.2 * defaultBitmapPoolSize);  

Since we've figured out our memory cache and bitmap pool sizes, we can finally get to code our Glide module. In the applyOptions() method, we can call the appropriate methods on the GlideBuilder object:

Glide 4.x

@GlideModule
public class CustomCachingGlideModule extends AppGlideModule {  
    @Override
    public void applyOptions(Context context, GlideBuilder builder) {
        MemorySizeCalculator calculator = new MemorySizeCalculator.Builder(context).build();
        int defaultMemoryCacheSize = calculator.getMemoryCacheSize();
        int defaultBitmapPoolSize = calculator.getBitmapPoolSize();

        int customMemoryCacheSize = (int) (1.2 * defaultMemoryCacheSize);
        int customBitmapPoolSize = (int) (1.2 * defaultBitmapPoolSize);

        builder.setMemoryCache(new LruResourceCache(customMemoryCacheSize));
        builder.setBitmapPool(new LruBitmapPool(customBitmapPoolSize));
    }

    @Override
    public void registerComponents(Context context, Glide glide, Registry registry) {
        // nothing to do here
    }
}

Glide 3.x

public class CustomCachingGlideModule implements GlideModule {  
    @Override public void applyOptions(Context context, GlideBuilder builder) {
        MemorySizeCalculator calculator = new MemorySizeCalculator(context);
        int defaultMemoryCacheSize = calculator.getMemoryCacheSize();
        int defaultBitmapPoolSize = calculator.getBitmapPoolSize();

        int customMemoryCacheSize = (int) (1.2 * defaultMemoryCacheSize);
        int customBitmapPoolSize = (int) (1.2 * defaultBitmapPoolSize);

        builder.setMemoryCache( new LruResourceCache( customMemoryCacheSize );
        builder.setBitmapPool( new LruBitmapPool( customBitmapPoolSize );
    }

    @Override public void registerComponents(Context context, Glide glide) {
        // nothing to do here
    }
}

As you can see from the last two lines in the applyOptions() method, we can't set the size directly. We're creating an instance of the LruResourceCache and the LruBitmapPool class. Both are the default implementations of Glide. Thus, if you only want to adjust the size, you can just continue to use them by just passing a different size value to the constructor.

Customize Disk Cache

Adjusting the size of the disk cache works very similar, but we've one decision more to make. The disk cache can be located in the apps private directory (in other words, no app has access to it, except your own). Otherwise, the disk cache can also be located on the external, public directory (for more information, see Storage Options). A combination of both locations is not possible with the default settings. Glide offers an implementation for either one of the two options with the InternalCacheDiskCacheFactory and ExternalCacheDiskCacheFactory. Just like the memory cache constructor, both disk cache factories accept a size value in their constructor:

Glide 4.x

@GlideModule
public class CustomCachingGlideModule extends AppGlideModule {  
    @Override
    public void applyOptions(Context context, GlideBuilder builder) {
        // set disk cache size & external vs. internal
        int cacheSize100MegaBytes = 104857600;

        builder.setDiskCache(
                new InternalCacheDiskCacheFactory(context, cacheSize100MegaBytes));

        //builder.setDiskCache(
        //        new ExternalCacheDiskCacheFactory(context, cacheSize100MegaBytes));
    }

    @Override
    public void registerComponents(Context context, Glide glide, Registry registry) {
        // nothing to do here
    }
}

Glide 3.x

public class CustomCachingGlideModule implements GlideModule {  
    @Override
    public void applyOptions(Context context, GlideBuilder builder) {
        // set disk cache size & external vs. internal
        int cacheSize100MegaBytes = 104857600;

        builder.setDiskCache(
            new InternalCacheDiskCacheFactory(context, cacheSize100MegaBytes)
        );

        //builder.setDiskCache(
        //new ExternalCacheDiskCacheFactory(context, cacheSize100MegaBytes));
    }

    @Override
    public void registerComponents(Context context, Glide glide) {
        // nothing to do here
    }
}

The code above would set the disk cache to the app's internal directory and also set the maximum size to 100 megabytes. The line, which is behind the comment slashes, would set the disk cache to the external directory (and also set the maximum size to 100 megabytes).

Both options you've seen above don't let you choose a specific directory. If you require to move the disk cache to some specific location, you can utilize the DiskLruCacheFactory:

Glide 4.x & Glide 3.x

// or any other path
String downloadDirectoryPath = Environment.getDownloadCacheDirectory().getPath(); 

builder.setDiskCache(  
        new DiskLruCacheFactory( downloadDirectoryPath, cacheSize100MegaBytes )
);

// In case you want to specify a cache sub folder (i.e. "glidecache"):
//builder.setDiskCache(
//    new DiskLruCacheFactory( downloadDirectoryPath, "glidecache", cacheSize100MegaBytes ) 
//);

Use the upper option to set a directory directly. The bottom option would create and use a directory inside your passed directory path. As always, the last parameter is the size of the cache in bytes.

Custom Cache Implementations

So far, we've shown you how to move and set the cache to certain sizes. However, all calls referred to the original implementation of the caches. What if you have your own cache implementation?

Well, you've seen we always created a new instance of Glide's default cache implementation. You can finish your own implementation, create and instance of it and pass it in all the methods you've seen above. You just have to make sure that your cache code implements the interface methods:

Outlook

In this tutorial, you've seen how to change and customize Glide's caches. Glide's default implementation is well-rounded, so make sure you've reasons to change things. If you do change something, make sure to test it on a range of devices!

In the next tutorial, we'll look at another Glide module topic. We'll look at how to implement a component, which requests the images in the exact size of the target ImageView. We promise, it'll be good!

Explore the Library

Find interesting tutorials and solutions for your problems.