Glideのディスクキャッシュ処理のメモ

ディスクキャッシュのインスタンスの生成

ディスクキャッシュの処理を行うインスタンスは、 Glide.Builder で設定した DiskCache.Factory から作成されます。もしBuilderで設定しない場合は InternalCacheDiskCacheFactory が使われます。

if (diskCacheFactory == null) {
    diskCacheFactory = new InternalCacheDiskCacheFactory(context);
}

https://github.com/bumptech/glide/blob/v4.11.0/library/src/main/java/com/bumptech/glide/GlideBuilder.java#L540

InternalCacheDiskCacheFactory

InternalCacheDiskCacheFactoryDiskLruCacheFactory を継承しているクラスとなっていて、 名前からLRUキャッシュが関係していそうなことが分かります。

InternalCacheDiskCacheFactory のコンストラクタは以下のようになっています。
キャッシュサイズは DiskCache.Factory.DEFAULT_DISK_CACHE_SIZE = 250MB 、保存場所はアプリのキャッシュディレクトリ内が指定されているようです。

public InternalCacheDiskCacheFactory(Context context) {
    this(
        context,
        DiskCache.Factory.DEFAULT_DISK_CACHE_DIR,
        DiskCache.Factory.DEFAULT_DISK_CACHE_SIZE);
}

public InternalCacheDiskCacheFactory(
    final Context context,
    final String diskCacheName,
    long diskCacheSize
) {
    super(
        new CacheDirectoryGetter() {
            @Override
            public File getCacheDirectory() {
                File cacheDirectory = context.getCacheDir();
                if (cacheDirectory == null) {
                    return null;
                }
                if (diskCacheName != null) {
                    return new File(cacheDirectory, diskCacheName);
                }
                return cacheDirectory;
            }
        },
        diskCacheSize);
}

DiskLruCacheFactoryが生成するクラス

InternalCacheDiskCacheFactory が継承している DiskLruCacheFactory とファクトリが生成するクラスについてみていきます。
DiskLruCacheFactoryDiskCache のクラスを生成するための DiskCache.Factory インタフェースを実装しています。
DiskCache を生成する処理はいかのようになっており、 DiskLruCacheWrapper を生成していることが分かりました。

public DiskCache build() {
    ...
    return DiskLruCacheWrapper.create(cacheDir, diskCacheSize);
}

DiskCacheインタフェースについて

ここまでで、 DiskCache の実装クラスとして DiskLruCacheWrapper が使用されることが分かりました。
そもそも DiskCache はどのようなインターフェースなのかをみておきます。

DiskCache は以下のように、キャッシュキーを元にファイルを取得したり保存したりするためのメソッドが4つだけあります。 DiskCache.Writer は指定されたファイルへデータを書き込むためのインタフェースになっています。

void clear()
void delete(Key key)
File get(Key key)
void put(Key key, DiskCache.Writer writer)

DiskCache (glide API)

DiskLruCacheWrapperの処理

DiskCache インタフェースの役割を確認できたので、実際にどのような処理が行われているかをみていきたいと思いますが、 DiskLruCacheWrapper はクラス名の通り DiskLruCache をラップしたクラスとなっていて、キャッシュに関する主要な処理のほとんどは DiskLruCache で行われています。 DiskLruCache の生成処理は以下のようになっています。

private synchronized DiskLruCache getDiskCache() throws IOException {
    if (diskLruCache == null) {
        diskLruCache = DiskLruCache.open(directory, APP_VERSION, VALUE_COUNT, maxSize);
    }
    return diskLruCache;
}

DiskLruCacheWrapper では DiskLruCache を扱うために、キャッシュキー(Key型)を String へ変換する処理も行っています。
キーの変換処理は SafeKeyGeneratorcalculateHexStringDigest で行われ、 Key#updateDiskCacheKey から取得できるバイト配列をSHA256でハッシュ化しているようです。

return Util.sha256BytesToHex(container.messageDigest.digest());

まとめ

Glideのデフォルトのディスクキャッシュは、LRUキャッシュで250MBまでキャッシュされることが分かりました。
(ちなみにドキュメントに書いてあります Glide v4 : Configuration - Disk Cache)

途中で出てきたキャッシュキー Key に使われる値については Glide v4 : Caching に記述があります。

In Glide 4, all cache keys contain at least two elements:

  1. The model the load is requested for (File, Uri, Url). If you are using a custom model, it needs to > correctly implements hashCode() and equals()
  2. An optional Signature

In fact, the cache keys for steps 1-3 (Active resources, memory cache, resource disk cache) also > include a number of other pieces of data including:

  1. The width and height
  2. The optional Transformation
  3. Any added Options
  4. The requested data type (Bitmap, GIF, etc)

デバッグの際には Engine タグで出力されるログが参考になります

adb shell setprop log.tag.Engine VERBOSE
V/Engine: Started new load in 0.594687ms, key: EngineKey{
    model=content://media/external/images/media/322064,
    width=1050,
    height=1560,
    resourceClass=class java.lang.Object, 
    transcodeClass=class android.graphics.drawable.Drawable, 
    signature=com.bumptech.glide.signature.MediaStoreSignature@9ccb4e57,
    hashCode=-1605280832,
    transformations={class android.graphics.drawable.Drawable=com.bumptech.glide.load.resource.bitmap.DrawableTransformation@5db7ce1d, class android.graphics.Bitmap=com.bumptech.glide.load.resource.bitmap.FitCenter@5db7ce1d, class com.bumptech.glide.load.resource.gif.GifDrawable=com.bumptech.glide.load.resource.gif.GifDrawableTransformation@5db7ce1d, class android.graphics.drawable.BitmapDrawable=com.bumptech.glide.load.resource.bitmap.DrawableTransformation@5db7ce1d},
    options=Options{values={Option{key='com.bumptech.glide.load.resource.bitmap.Downsampler.DownsampleStrategy'}=com.bumptech.glide.load.resource.bitmap.DownsampleStrategy$FitCenter@2fc7c43}}}