Glide: Can I use different disk cache folders for different scenarios?

Created on 9 Oct 2017  ·  5Comments  ·  Source: bumptech/glide

Glide Version:4.1.1

Device/Android Version:

Issue details / Repro steps / Use case background:

I use Glide to download small contact images and big pictures in chat. If they are stored in the same disk cache directory, the small images will be removed from disk cache unexpectedly because pictures in chat are much bigger than them.

So I want to store the two types of pictures of my app in different disk cache folders. But Glide doesn't seem to support this?

question

Most helpful comment

@sjudd I have implemented a DiskLruCacheWrapper that can select different disk cache folders by the signature. Thanks for your help!
MultiFolderDiskLruCacheWrapper.java

/**
 * 支持多个磁盘缓存目录
 */
public class MultiFolderDiskLruCacheWrapper extends DiskLruCacheWrapper {
  private static final String TAG = "MultiFolderDiskLruCacheWrapper";

  private static Field sFieldSignatureInResourceCacheKey;
  private static Field sFieldSignatureInDataCacheKey;
  private static MultiFolderDiskLruCacheWrapper wrapper;

  static {
    try {
      Class<?> resourceCacheKeyClass = Class.forName("com.bumptech.glide.load.engine.ResourceCacheKey");
      sFieldSignatureInResourceCacheKey = resourceCacheKeyClass.getDeclaredField("signature");
      sFieldSignatureInResourceCacheKey.setAccessible(true);

      Class<?> DataCacheKeyClass = Class.forName("com.bumptech.glide.load.engine.DataCacheKey");
      sFieldSignatureInDataCacheKey = DataCacheKeyClass.getDeclaredField("signature");
      sFieldSignatureInDataCacheKey.setAccessible(true);
    } catch (ClassNotFoundException e) {
      WwLog.log(Log.WARN, TAG, "find ResourceCacheKey failed", e);
    } catch (NoSuchFieldException e) {
      WwLog.log(Log.WARN, TAG, "reflect signature failed", e);
    } catch (Error error) {
      WwLog.log(Log.WARN, TAG, "reflect signature failed", error);
    }
  }

  private DiskCache[] diskCaches = new DiskCache[CacheFolder.values().length];

  public static synchronized DiskCache get() {
    if (wrapper == null) {
      wrapper = new MultiFolderDiskLruCacheWrapper(null, 0);
    }
    return wrapper;
  }

  protected MultiFolderDiskLruCacheWrapper(File directory, int maxSize) {
    super(directory, maxSize);
  }

  @Override
  public File get(Key key) {
    return getDiskCacheBySignature(key).get(key);
  }

  @Override
  public void put(Key key, Writer writer) {
    getDiskCacheBySignature(key).put(key, writer);
  }

  @Override
  public void delete(Key key) {
    getDiskCacheBySignature(key).delete(key);
  }

  @Override
  public synchronized void clear() {
    for (DiskCache diskCache : diskCaches) {
      if (diskCache != null) {
        diskCache.clear();
      }
    }
  }

  /**
   * 根据key选择不同的DiskCache实例,每个DiskCache实例对应不同缓存目录
   * @param key
   * @return
   */
  private DiskCache getDiskCacheBySignature(Key key) {
    Object signature = getSignature(key);
    CacheFolder cacheFolder;
    if (isContact(signature)) {
      cacheFolder = CacheFolder.CONTACHT;
    } else {
      cacheFolder = CacheFolder.OTHER;
    }

    return getDiskCache(cacheFolder);
  }

  @Nullable
  private Object getSignature(Key key) {
    Object signature = null;
    try { // 已有缓存的情况下一般是ResourceCacheKey,所以这种情况更常见
      signature = sFieldSignatureInResourceCacheKey.get(key);
    } catch (Exception e) {
      WwLog.log(Log.INFO, TAG, "getSignature: " + e.getMessage());
    }
    if (signature != null) return  signature;

    try {
      signature = sFieldSignatureInDataCacheKey.get(key);
    } catch (Exception e) {
      WwLog.log(Log.INFO, TAG, "getSignature", e);
    }
    return signature;
  }

  private boolean isContact(Object signature) {
    return signature instanceof ContactSignature;
  }

  @NonNull
  private DiskCache getDiskCache(CacheFolder cacheFolder) {
    DiskCache diskCache = diskCaches[cacheFolder.index];
    if (diskCache == null) {
      String cachePath = FileUtil.getImageDiskCacheDirPath(cacheFolder.cacheDirName);
      if (FileUtil.createDir(cachePath)) {
        try {
          diskCache = (DiskLruCacheWrapper) ReflecterHelper.newInstance(
                  "com.bumptech.glide.load.engine.cache.DiskLruCacheWrapper", new Object[]{new File(cachePath), cacheFolder.cacheSize});
          diskCaches[cacheFolder.index] = diskCache;
        } catch (Exception e) {
          WwLog.log(Log.ERROR, TAG, "getDiskCache", e);
        }

      }
    }
    return diskCache;
  }
}

CacheFolder.java

public enum CacheFolder {
    CONTACHT(0, 1024 * 1024 * 50, "glidecontactphoto"),

    IMAGE(1, 1024 * 1024 * 100, "glideimage"),

    OTHER(2, 1024 * 1024 * 50, "glideother"),
    ;

    public int index;
    public int cacheSize;
    public String cacheDirName;

    CacheFolder(int index, int cacheSize, String cacheDirName) {
        this.index = index;
        this.cacheSize = cacheSize;
        this.cacheDirName = cacheDirName;
    }
}

All 5 comments

Glide's default disk cache is LRU in a single folder, but you can always write a new implementation: http://bumptech.github.io/glide/doc/configuration.html#disk-cache.

There's some discussion of how to handle similar cases in #792 and #1033.

This issue has been automatically marked as stale because it has not had activity in the last seven days. It will be closed if no further activity occurs within the next seven days. Thank you for your contributions.

@sjudd I have implemented a DiskLruCacheWrapper that can select different disk cache folders by the signature. Thanks for your help!
MultiFolderDiskLruCacheWrapper.java

/**
 * 支持多个磁盘缓存目录
 */
public class MultiFolderDiskLruCacheWrapper extends DiskLruCacheWrapper {
  private static final String TAG = "MultiFolderDiskLruCacheWrapper";

  private static Field sFieldSignatureInResourceCacheKey;
  private static Field sFieldSignatureInDataCacheKey;
  private static MultiFolderDiskLruCacheWrapper wrapper;

  static {
    try {
      Class<?> resourceCacheKeyClass = Class.forName("com.bumptech.glide.load.engine.ResourceCacheKey");
      sFieldSignatureInResourceCacheKey = resourceCacheKeyClass.getDeclaredField("signature");
      sFieldSignatureInResourceCacheKey.setAccessible(true);

      Class<?> DataCacheKeyClass = Class.forName("com.bumptech.glide.load.engine.DataCacheKey");
      sFieldSignatureInDataCacheKey = DataCacheKeyClass.getDeclaredField("signature");
      sFieldSignatureInDataCacheKey.setAccessible(true);
    } catch (ClassNotFoundException e) {
      WwLog.log(Log.WARN, TAG, "find ResourceCacheKey failed", e);
    } catch (NoSuchFieldException e) {
      WwLog.log(Log.WARN, TAG, "reflect signature failed", e);
    } catch (Error error) {
      WwLog.log(Log.WARN, TAG, "reflect signature failed", error);
    }
  }

  private DiskCache[] diskCaches = new DiskCache[CacheFolder.values().length];

  public static synchronized DiskCache get() {
    if (wrapper == null) {
      wrapper = new MultiFolderDiskLruCacheWrapper(null, 0);
    }
    return wrapper;
  }

  protected MultiFolderDiskLruCacheWrapper(File directory, int maxSize) {
    super(directory, maxSize);
  }

  @Override
  public File get(Key key) {
    return getDiskCacheBySignature(key).get(key);
  }

  @Override
  public void put(Key key, Writer writer) {
    getDiskCacheBySignature(key).put(key, writer);
  }

  @Override
  public void delete(Key key) {
    getDiskCacheBySignature(key).delete(key);
  }

  @Override
  public synchronized void clear() {
    for (DiskCache diskCache : diskCaches) {
      if (diskCache != null) {
        diskCache.clear();
      }
    }
  }

  /**
   * 根据key选择不同的DiskCache实例,每个DiskCache实例对应不同缓存目录
   * @param key
   * @return
   */
  private DiskCache getDiskCacheBySignature(Key key) {
    Object signature = getSignature(key);
    CacheFolder cacheFolder;
    if (isContact(signature)) {
      cacheFolder = CacheFolder.CONTACHT;
    } else {
      cacheFolder = CacheFolder.OTHER;
    }

    return getDiskCache(cacheFolder);
  }

  @Nullable
  private Object getSignature(Key key) {
    Object signature = null;
    try { // 已有缓存的情况下一般是ResourceCacheKey,所以这种情况更常见
      signature = sFieldSignatureInResourceCacheKey.get(key);
    } catch (Exception e) {
      WwLog.log(Log.INFO, TAG, "getSignature: " + e.getMessage());
    }
    if (signature != null) return  signature;

    try {
      signature = sFieldSignatureInDataCacheKey.get(key);
    } catch (Exception e) {
      WwLog.log(Log.INFO, TAG, "getSignature", e);
    }
    return signature;
  }

  private boolean isContact(Object signature) {
    return signature instanceof ContactSignature;
  }

  @NonNull
  private DiskCache getDiskCache(CacheFolder cacheFolder) {
    DiskCache diskCache = diskCaches[cacheFolder.index];
    if (diskCache == null) {
      String cachePath = FileUtil.getImageDiskCacheDirPath(cacheFolder.cacheDirName);
      if (FileUtil.createDir(cachePath)) {
        try {
          diskCache = (DiskLruCacheWrapper) ReflecterHelper.newInstance(
                  "com.bumptech.glide.load.engine.cache.DiskLruCacheWrapper", new Object[]{new File(cachePath), cacheFolder.cacheSize});
          diskCaches[cacheFolder.index] = diskCache;
        } catch (Exception e) {
          WwLog.log(Log.ERROR, TAG, "getDiskCache", e);
        }

      }
    }
    return diskCache;
  }
}

CacheFolder.java

public enum CacheFolder {
    CONTACHT(0, 1024 * 1024 * 50, "glidecontactphoto"),

    IMAGE(1, 1024 * 1024 * 100, "glideimage"),

    OTHER(2, 1024 * 1024 * 50, "glideother"),
    ;

    public int index;
    public int cacheSize;
    public String cacheDirName;

    CacheFolder(int index, int cacheSize, String cacheDirName) {
        this.index = index;
        this.cacheSize = cacheSize;
        this.cacheDirName = cacheDirName;
    }
}

@sjudd

is @LuYeCong implementation still the best and only way to do it ?

@haniha Nothing has changed here yet.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Tryking picture Tryking  ·  3Comments

mttmllns picture mttmllns  ·  3Comments

sergeyfitis picture sergeyfitis  ·  3Comments

sant527 picture sant527  ·  3Comments

Morteza-Rastgoo picture Morteza-Rastgoo  ·  3Comments