Glide获取某个url对应的缓存图片

用Glide这么久了,我一直有个疑问,Glide该如何获取到指定的缓存图片?

原生Glide是没有提供任何Api用来获取缓存图片的,至少我是没找到。

翻看Glide源码(3.7),发现其中一个叫:EngineKey的类,Glide通过该类来查找对应的缓存文件。
该类构造方法参数多达10个,并且不是开放出来的,也就是说,通过自己构造EngineKey这条路是走不通的。

难道就没有办法了吗?仔细翻看EngineKey这个类,其中有一个叫getOriginalKey的方法:

public Key getOriginalKey() {
    if (originalKey == null) {
        originalKey = new OriginalKey(id, signature);
    }
    return originalKey;
}

对应OriginalKey只需要两个参数,并且类的内容也很简单:

class OriginalKey implements Key {

    private final String id;
    private final Key signature;

    public OriginalKey(String id, Key signature) {
        this.id = id;
        this.signature = signature;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }

        OriginalKey that = (OriginalKey) o;

        if (!id.equals(that.id)) {
            return false;
        }
        if (!signature.equals(that.signature)) {
            return false;
        }

        return true;
    }

    @Override
    public int hashCode() {
        int result = id.hashCode();
        result = 31 * result + signature.hashCode();
        return result;
    }

    @Override
    public void updateDiskCacheKey(MessageDigest messageDigest) throws UnsupportedEncodingException {
        messageDigest.update(id.getBytes(STRING_CHARSET_NAME));
        signature.updateDiskCacheKey(messageDigest);
    }
}

再查看getOriginalKey()方法的调用者,发现被一个DecodeJob的两个方法调用到了:

private Resource<T> cacheAndDecodeSourceData(A data) throws IOException {
    long startTime = LogTime.getLogTime();
    SourceWriter<A> writer = new SourceWriter<A>(loadProvider.getSourceEncoder(), data);
    diskCacheProvider.getDiskCache().put(resultKey.getOriginalKey(), writer);
    if (Log.isLoggable(TAG, Log.VERBOSE)) {
        logWithTimeAndKey("Wrote source to cache", startTime);
    }

    startTime = LogTime.getLogTime();
    Resource<T> result = loadFromCache(resultKey.getOriginalKey());
    if (Log.isLoggable(TAG, Log.VERBOSE) && result != null) {
        logWithTimeAndKey("Decoded source from cache", startTime);
    }
    return result;
}

public Resource<Z> decodeSourceFromCache() throws Exception {
    if (!diskCacheStrategy.cacheSource()) {
        return null;
    }

    long startTime = LogTime.getLogTime();
    Resource<T> decoded = loadFromCache(resultKey.getOriginalKey());
    if (Log.isLoggable(TAG, Log.VERBOSE)) {
        logWithTimeAndKey("Decoded source from cache", startTime);
    }
    return transformEncodeAndTranscode(decoded);
}

了解过Glide源码的人应该知道,这两个方法是在diskCacheStrategy设置为Source时,Glide缓存到本地和从本地取缓存的方法。

查看loadFromCache方法:

private Resource<T> loadFromCache(Key key) throws IOException {
    File cacheFile = diskCacheProvider.getDiskCache().get(key);
    if (cacheFile == null) {
        return null;
    }

    Resource<T> result = null;
    try {
        result = loadProvider.getCacheDecoder().decode(cacheFile, width, height);
    } finally {
        if (result == null) {
            diskCacheProvider.getDiskCache().delete(key);
        }
    }
    return result;
}

get方法点进去,发现有两个实现:DiskCacheAdapter和DiskLruCacheWrapper,DiskCacheAdapter只是个空壳,那么只有DiskLruCacheWrapper了。

其中获取缓存文件的方法:

@Override
public File get(Key key) {
    String safeKey = safeKeyGenerator.getSafeKey(key);
    File result = null;
    try {
        //It is possible that the there will be a put in between these two gets. If so that shouldn't be a problem
        //because we will always put the same value at the same key so our input streams will still represent
        //the same data
        final DiskLruCache.Value value = getDiskCache().get(safeKey);
        if (value != null) {
            result = value.getFile(0);
        }
    } catch (IOException e) {
        if (Log.isLoggable(TAG, Log.WARN)) {
            Log.w(TAG, "Unable to get from disk cache", e);
        }
    }
    return result;
}

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

那就好办了!我们只需将diskCacheStrategy设置为Source,然后自己构造OriginalKey和DiskLruCache即可。

说干就干!

将Glide下的SafeKeyGenerator和OriginalKey类拷到自己的包下,这两个类也很简单:

/**
 * A class that generates and caches safe and unique string file names from {@link com.bumptech.glide.load.Key}s.
 */
class SafeKeyGenerator {
    private final LruCache<Key, String> loadIdToSafeHash = new LruCache<Key, String>(1000);

    public String getSafeKey(Key key) {
        String safeKey;
        synchronized (loadIdToSafeHash) {
            safeKey = loadIdToSafeHash.get(key);
        }
        if (safeKey == null) {
            try {
                MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
                key.updateDiskCacheKey(messageDigest);
                safeKey = Util.sha256BytesToHex(messageDigest.digest());
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
            synchronized (loadIdToSafeHash) {
                loadIdToSafeHash.put(key, safeKey);
            }
        }
        return safeKey;
    }
}

//OriginalKey 在上面!

然后就可以获取缓存文件了,如果你没有自己构造Signature和修改磁盘缓存位置,那用下面这个方法即可:

//3.7
public File getCacheFile(String url) {
    OriginalKey originalKey = new OriginalKey(url, EmptySignature.obtain());
    SafeKeyGenerator safeKeyGenerator = new SafeKeyGenerator();
    String safeKey = safeKeyGenerator.getSafeKey(originalKey);
    try {
        DiskLruCache diskLruCache = DiskLruCache.open(new File(getCacheDir(), DiskCache.Factory.DEFAULT_DISK_CACHE_DIR), 1, 1, DiskCache.Factory.DEFAULT_DISK_CACHE_SIZE);
        DiskLruCache.Value value = diskLruCache.get(safeKey);
        if (value != null) {
            return value.getFile(0);
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
    return null;
}

效果:
这里写图片描述

当然,如果不是Glide3.7,而是4.x呢?额,亲测在4.0上只需要改一个类即可(其他的4.x就不知道了<( ̄︶ ̄)>),将OriginalKey换为DataCacheKey即可:

/**
 * A cache key for original source data + any requested signature.
 */
public class DataCacheKey implements Key  {

    private final Key sourceKey;
    private final Key signature;

    public DataCacheKey(Key sourceKey, Key signature) {
        this.sourceKey = sourceKey;
        this.signature = signature;
    }

    public Key getSourceKey() {
        return sourceKey;
    }

    @Override
    public boolean equals(Object o) {
        if (o instanceof DataCacheKey) {
            DataCacheKey other = (DataCacheKey) o;
            return sourceKey.equals(other.sourceKey) && signature.equals(other.signature);
        }
        return false;
    }

    @Override
    public int hashCode() {
        int result = sourceKey.hashCode();
        result = 31 * result + signature.hashCode();
        return result;
    }

    @Override
    public String toString() {
        return "DataCacheKey{"
                + "sourceKey=" + sourceKey
                + ", signature=" + signature
                + '}';
    }

    @Override
    public void updateDiskCacheKey(MessageDigest messageDigest) {
        sourceKey.updateDiskCacheKey(messageDigest);
        signature.updateDiskCacheKey(messageDigest);
    }
}

对应的方法:

//4.0
public File getCacheFile2(String url) {
    DataCacheKey dataCacheKey = new DataCacheKey(new GlideUrl(url), EmptySignature.obtain());
    SafeKeyGenerator safeKeyGenerator = new SafeKeyGenerator();
    String safeKey = safeKeyGenerator.getSafeKey(dataCacheKey);
    try {
        int cacheSize = 100 * 1000 * 1000;
        DiskLruCache diskLruCache = DiskLruCache.open(new File(getCacheDir(), DiskCache.Factory.DEFAULT_DISK_CACHE_DIR), 1, 1, cacheSize);
        DiskLruCache.Value value = diskLruCache.get(safeKey);
        if (value != null) {
            return value.getFile(0);
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
    return null;
}

一个非常简单的Demo : https://github.com/HuangShengHuan/GlideCache

  • 9
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 15
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值