美文网首页
Glide 缓存机制-源码解析

Glide 缓存机制-源码解析

作者: pj0579 | 来源:发表于2019-10-24 22:37 被阅读0次

    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<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;
    }
    

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

    public Resource<Z> decodeFromSource() throws Exception {
        Resource<T> decoded = decodeSource();
        return transformEncodeAndTranscode(decoded);
    }
    private Resource<T> decodeSource() throws Exception {
        Resource<T> 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<T> decodeFromSourceData(A data) throws IOException {
        final Resource<T> decoded;
        if (diskCacheStrategy.cacheSource()) {
            decoded = cacheAndDecodeSourceData(data);
        } else {
            long startTime = LogTime.getLogTime();
            decoded = loadProvider.getSourceDecoder().decode(data, width, height);
        }
        return decoded;
    }
    
    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);
        startTime = LogTime.getLogTime();
        Resource<T> result = loadFromCache(resultKey.getOriginalKey());
        return result;
    }
    

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

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

    相关文章

      网友评论

          本文标题:Glide 缓存机制-源码解析

          本文链接:https://www.haomeiwen.com/subject/dtbdvctx.html