Glide 缓存机制-源码解析

Glide分为内存缓存和硬盘缓存两种
内存缓存默认开启,使用的算法是LruCache算法(Least Recently Used),最近最少使用算法。主要原理是对象的强引用存储在LinkedHashMap中,达到预设定的值淘汰最近最少使用的对象,除了Lru外还结合了弱引用。
下面来看下源码

private EngineResource loadFromCache(Key key, boolean isMemoryCacheable) {
        if (!isMemoryCacheable) {
            // 通过 skipMemoryCache() 设置
            return null;
        }
        // 对于不同的key 获取不同的缓存 获取后从缓存中删除
        EngineResource cached = getEngineResourceFromCache(key);
        if (cached != null) {
            // 获得缓存后 存储弱引用Map中 保护不会被LruCache回收掉
            cached.acquire();
            activeResources.put(key, new ResourceWeakReference(key, cached, getReferenceQueue()));
        }
        return cached;
    }

那这个缓存是什么时候写进去的?当然是从网络获取后存进去,之前文章分析的handleResultOnMainThread方法。

 private void handleResultOnMainThread() {
        if (isCancelled) {
            resource.recycle();
            return;
        } else if (cbs.isEmpty()) {
            throw new IllegalStateException("Received a resource without any callbacks to notify");
        }
        engineResource = engineResourceFactory.build(resource, isCacheable);
        hasResource = true;
        engineResource.acquire();
        listener.onEngineJobComplete(key, engineResource);
        for (ResourceCallback cb : cbs) {
            if (!isInIgnoredCallbacks(cb)) {
                engineResource.acquire();
                cb.onResourceReady(engineResource);
            }
        }
        engineResource.release();
    }

在onEngineJobComplete方法里进行了缓存

 public void onEngineJobComplete(Key key, EngineResource resource) {
        Util.assertMainThread();
        // A null resource indicates that the load failed, usually due to an exception.
        if (resource != null) {
            resource.setResourceListener(key, this);
            if (resource.isCacheable()) {
                activeResources.put(key, new ResourceWeakReference(key, resource, getReferenceQueue()));
            }
        }
        jobs.remove(key);
    }

在上面代码可以看出 缓存先放在了弱引用map中,engineResource.acquire()会对EngineResource的引用计数+1 ,release会对计数-1,当计数=0的时候在LruCache里,当计数大于1的时候在弱引用中,在release的时候会进行判断,计数=0的时候会放入到LruCache中

void release() {
        if (acquired <= 0) {
            throw new IllegalStateException("Cannot release a recycled or not yet acquired resource");
        }
        if (!Looper.getMainLooper().equals(Looper.myLooper())) {
            throw new IllegalThreadStateException("Must call release on the main thread");
        }
        if (--acquired == 0) {
             // 在这放入LruCache中
            listener.onResourceReleased(key, this);
        }
    }

再来看下硬盘缓存

private Resource loadFromCache(Key key) throws IOException {
    File cacheFile = diskCacheProvider.getDiskCache().get(key);
    if (cacheFile == null) {
        return null;
    }
    Resource result = null;
    try {
        result = loadProvider.getCacheDecoder().decode(cacheFile, width, height);
    } finally {
        if (result == null) {
            diskCacheProvider.getDiskCache().delete(key);
        }
    }
    return result;
}

那么硬盘缓存是怎么写入的呢? 没有缓存的时候调用decodeFromSource(

public Resource decodeFromSource() throws Exception {
    Resource decoded = decodeSource();
    return transformEncodeAndTranscode(decoded);
}
private Resource decodeSource() throws Exception {
    Resource decoded = null;
    try {
        long startTime = LogTime.getLogTime();
        final A data = fetcher.loadData(priority);
        if (isCancelled) {
            return null;
        }
        decoded = decodeFromSourceData(data);
    } finally {
        fetcher.cleanup();
    }
    return decoded;
}

private Resource decodeFromSourceData(A data) throws IOException {
    final Resource decoded;
    if (diskCacheStrategy.cacheSource()) {
        decoded = cacheAndDecodeSourceData(data);
    } else {
        long startTime = LogTime.getLogTime();
        decoded = loadProvider.getSourceDecoder().decode(data, width, height);
    }
    return decoded;
}

private Resource cacheAndDecodeSourceData(A data) throws IOException {
    long startTime = LogTime.getLogTime();
    SourceWriter writer = new SourceWriter(loadProvider.getSourceEncoder(), data);
    diskCacheProvider.getDiskCache().put(resultKey.getOriginalKey(), writer);
    startTime = LogTime.getLogTime();
    Resource result = loadFromCache(resultKey.getOriginalKey());
    return result;
}

先调用fetcher的loadData()方法读取图片数据,然后调用decodeFromSourceData()方法来对图片进行解码。接下来会判断是否允许缓存原始图片,如果允许的话又会调用cacheAndDecodeSourceData()方法。而在这个方法中同样调用了getDiskCache()方法来获取DiskLruCache实例,接着调用它的put()方法就可以写入硬盘缓存。

总结:
Glide还在缓存的顺序:内存缓存(LruCache缓存和弱引用缓存靠计数转换)->硬盘缓存->网络请求

你可能感兴趣的:(Glide 缓存机制-源码解析)