本文共 5385 字,大约阅读时间需要 17 分钟。
Glide
类中与内存缓存有关的变量Glide#memoryCache
,如果用户没有通过 GlideBuilder#setMemoryCache(MemoryCache)
设置,则默认为 LruResourceCache
(继承自 LruCache
)。
在 Engine#load()
方法中,就先根据需要加载的资源的相关参数,来生成唯一的 key
值,而该值与从缓存机制有关。
// Engine.javapublic synchronizedLoadStatus load(...) { long startTime = VERBOSE_IS_LOGGABLE ? LogTime.getLogTime() : 0; // 首先根据目标资源的相关参数得到对应的 key 值 EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations, resourceClass, transcodeClass, options); //(1)先从 ActiveResources 里面去获取 EngineResource active = loadFromActiveResources(key, isMemoryCacheable); if (active != null) { cb.onResourceReady(active, DataSource.MEMORY_CACHE); if (VERBOSE_IS_LOGGABLE) { logWithTimeAndKey("Loaded resource from active resources", startTime, key); } return null; } // (2)如果没有,则从内存缓存中去获取 EngineResource cached = loadFromCache(key, isMemoryCacheable); if (cached != null) { cb.onResourceReady(cached, DataSource.MEMORY_CACHE); if (VERBOSE_IS_LOGGABLE) { logWithTimeAndKey("Loaded resource from cache", startTime, key); } return null; } // 在两个方法都没有获取到缓存的情况下,才会继续向下执行,从而开启线程来加载图片 ...}
(1) loadFromActiveResources()
private EngineResource loadFromActiveResources(Key key, boolean isMemoryCacheable) { // 先判断是否禁用内存缓存 if (!isMemoryCacheable) { return null; } // 从 activeResources 中去获取资源 EngineResource active = activeResources.get(key); if (active != null) { // 标记资源被引用数量 +1 active.acquire(); } return active;}
activeResources
为 ActiveResources
对象,其内部有一个 HashMap<Key, ResourceWeakReference>
,即持有着 key
值对应的资源对象的弱引用。
activeResources 的目的是为了 缓存正在使用中的图片,从而可以保护这些图片不会被 LruCache 算法回收掉。
(2) loadFromCache()
private EngineResource loadFromCache(Key key, boolean isMemoryCacheable) { if (!isMemoryCacheable) { return null; } // 从 LruCache 对应的内存缓存中去获取 EngineResource cached = getEngineResourceFromCache(key); if (cached != null) { cached.acquire(); // 将取出的资源添加到 activeResources 中 activeResources.activate(key, cached); } return cached;}private EngineResource getEngineResourceFromCache(Key key) { Resource cached = cache.remove(key); final EngineResource result; if (cached == null) { result = null; } else if (cached instanceof EngineResource) { // Save an object allocation if we've cached an EngineResource (the typical case). result = (EngineResource ) cached; } else { result = new EngineResource<>(cached, true /*isMemoryCacheable*/, true /*isRecyclable*/); } return result;}
loadFromCache()
则是从前面说的默认为 LruResourceCache
中去获取目标资源。如果目标资源存在,则如 LruResourceCache
中取出,并加入到前面说的 activeResources
中。
从内存缓存中读取资源的逻辑大概就是这些。概括一下来说,就是如果能从内存缓存当中读取到要加载的图片,那么就直接进行回调,如果读取不到的话,才会开启线程执行后面的图片加载逻辑。
补充,根据郭神的说的,对于内存缓存,使用到 ActiveResources
和 LruResourceCache
,目的是为了保护正在被使用的图片不会被 LruCache
算法回收掉。
Engine
类实现了 EngineJobListener
接口,当资源加载完成后,就回调 Engine#onEngineJobComplete()
方法。
// Engine.javapublic synchronized void onEngineJobComplete( EngineJob engineJob, Key key, EngineResource resource) { // A null resource indicates that the load failed, usually due to an exception. if (resource != null) { // 为 EngineResource 资源对象设置 ResourceListener 监听,即 Engine 对象自身, // 因为Engine 实现了 ResourceListener 接口。 resource.setResourceListener(key, this); // 如果资源允许被缓存,则将其添加到 activeResources 中 if (resource.isCacheable()) { activeResources.activate(key, resource); } } jobs.removeIfCurrent(key, engineJob);}
这里注意的是,加载好的资源并不是直接被缓存到 LruResourceCache
中的,而是先被缓存到 activeResources
中。
而缓存到 LruResourceCache
中,则与第 7 行设置 ResourceListener
有关。之前有说过 EngineResource#acquire()
方法,该方法中就使用 EngineResource
对象的成员变量 acquired
来记录图片资源被引用的次数,调用 acquire()
方法会让变量加 1,而调用 release()
方法则会使变量减 1。
也就是说,当 acquired
变量大于 0 的时候,说明图片正在使用中,也就应该放到 activeResources
弱引用缓存当中。而经过 release()
之后,如果 acquired
变量等于 0 了,说明图片已经 不是正在被使用状态 了。
void release() { synchronized (listener) { synchronized (this) { if (acquired <= 0) { throw new IllegalStateException("Cannot release a recycled or not yet acquired resource"); } // 当 acquired 为 0 的时候就会回调设置的 ResourceListener 接口的 onResourceReleased() 方法 if (--acquired == 0) { listener.onResourceReleased(key, this); } } }}
前面说 Engine
也实现了 ResourceListener
接口,
// Engine.javapublic synchronized void onResourceReleased(Key cacheKey, EngineResource resource) { activeResources.deactivate(cacheKey); if (resource.isCacheable()) { cache.put(cacheKey, resource); } else { resourceRecycler.recycle(resource); }}
在 onResourceReleased()
方法中,就会将已经不是正在被使用的图片资源从 activeResources
中移除,然后根据缓存状态,将其转移至 LruResourceCache
中,或者回收释放。
Glide 默认在磁盘中缓存的图片并不是原始的图片,而是经过一系列操作(如压缩、转换为目标高宽)转换来的(Resource)。当然也可以设置缓存原始图片(Source)。(因而两种图片对应的 key
值也是不同的)
DiskCacheStrategy.NONE: 表示不缓存任何内容。
DiskCacheStrategy.SOURCE: 表示只缓存原始图片。 DiskCacheStrategy.RESULT: 表示只缓存转换过后的图片(默认选项)。 DiskCacheStrategy.ALL : 表示既缓存原始图片,也缓存转换过后的图片。
磁盘缓存实现类由 InternalCacheDiskCacheFactory
创建,最终会通过缓存路径及缓存文件夹最大值创建一个 DiskLruCacheWrapper
对象。
DiskLruCacheWrapper
顾名思义是一个包装类,包装的是 DiskLruCache
。且实现了 DiskCache
接口,该接口定义了磁盘缓存的操作。
另外,内部还持有 SafeKeyGenerator
对象,该对象可以根据 Key
对象得到对应的字符串 key
值,而字符串 key
就是用于索引磁盘中缓存的图片资源的。
以及,在向磁盘写入文件时(put
方法)会使用重入锁来同步代码,也就是 DiskCacheWriteLocker
类,其中主要是对 ReentrantLock
的包装。
参考文章
1、 2、转载地址:http://yrerj.baihongyu.com/