Glide缓存分为内存缓存和磁盘缓存。
1. 内存缓存
在Engine#load方法中:
public <R> LoadStatus load(
GlideContext glideContext,
Object model,
Key signature,
int width,
int height,
Class<?> resourceClass,
Class<R> transcodeClass,
Priority priority,
DiskCacheStrategy diskCacheStrategy,
Map<Class<?>, Transformation<?>> transformations,
boolean isTransformationRequired,
boolean isScaleOnlyOrNoTransform,
Options options,
boolean isMemoryCacheable,
boolean useUnlimitedSourceExecutorPool,
boolean useAnimationPool,
boolean onlyRetrieveFromCache,
ResourceCallback cb,
Executor callbackExecutor) {
long startTime = VERBOSE_IS_LOGGABLE ? LogTime.getLogTime() : 0;
EngineKey key =
keyFactory.buildKey(
model,
signature,
width,
height,
transformations,
resourceClass,
transcodeClass,
options);
EngineResource<?> memoryResource;
synchronized (this) {
memoryResource = loadFromMemory(key, isMemoryCacheable, startTime);
if (memoryResource == null) {
return waitForExistingOrStartNewJob(
glideContext,
model,
signature,
width,
height,
resourceClass,
transcodeClass,
priority,
diskCacheStrategy,
transformations,
isTransformationRequired,
isScaleOnlyOrNoTransform,
options,
isMemoryCacheable,
useUnlimitedSourceExecutorPool,
useAnimationPool,
onlyRetrieveFromCache,
cb,
callbackExecutor,
key,
startTime);
}
}
@Nullable
private EngineResource<?> loadFromMemory(
EngineKey key, boolean isMemoryCacheable, long startTime) {
if (!isMemoryCacheable) {
return null;
}
EngineResource<?> active = loadFromActiveResources(key);
if (active != null) {
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Loaded resource from active resources", startTime, key);
}
return active;
}
EngineResource<?> cached = loadFromCache(key);
if (cached != null) {
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Loaded resource from cache", startTime, key);
}
return cached;
}
return null;
}
@Nullable
private EngineResource<?> loadFromActiveResources(Key key) {
EngineResource<?> active = activeResources.get(key);
if (active != null) {
active.acquire();
}
return active;
}
private EngineResource<?> loadFromCache(Key key) {
EngineResource<?> cached = getEngineResourceFromCache(key);
if (cached != null) {
cached.acquire();
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, /*isMemoryCacheable=*/ true, /*isRecyclable=*/ true, key, /*listener=*/ this);
}
return result;
}
可以看到,load方法在生成key之后,首先调用loadFromMemory方法从内存中加载,如果加载失败,则调用waitForExistingOrStartNewJob方法开启线程去加载。
在loadFromMemory方法中,首先判断是否开启缓存,默认是开启的,如果在skipMemoryCache中传入true,则跳过内存缓存:
private boolean isCacheable = true;
@NonNull
@CheckResult
public T skipMemoryCache(boolean skip) {
if (isAutoCloneEnabled) {
return clone().skipMemoryCache(true);
}
this.isCacheable = !skip;
fields |= IS_CACHEABLE;
return selfOrThrowIfLocked();
}
如果开启了内存缓存,则在loadFromMemory方法中先调用了loadFromActiveResources方法,加载使用WeakReference弱引用的仍在使用中的资源,并对资源调用acquire方法进行加一操作:
private final ActiveResources activeResources;
final class ActiveResources {
private final boolean isActiveResourceRetentionAllowed;
private final Executor monitorClearedResourcesExecutor;
@VisibleForTesting final Map<Key, ResourceWeakReference> activeEngineResources = new HashMap<>();
...
synchronized void activate(Key key, EngineResource<?> resource) {
ResourceWeakReference toPut =
new ResourceWeakReference(
key, resource, resourceReferenceQueue, isActiveResourceRetentionAllowed);
ResourceWeakReference removed = activeEngineResources.put(key, toPut);
if (removed != null) {
removed.reset();
}
}
@VisibleForTesting
static final class ResourceWeakReference extends WeakReference<EngineResource<?>> {
...
}
}
synchronized void acquire() {
if (isRecycled) {
throw new IllegalStateException("Cannot acquire a recycled resource");
}
++acquired;
}
如果没有找到active resource,则调用loadFromCache方法加载,调用cache#acquire方法,然后调用activeResources#activate将获取到的资源放入active resource中。
这里的cache是LruCache,使用Lru算法,Glide#with方法调用getRetriever->Glide#get->checkAndInitializeGlide->initializeGlide->找到一行代码:Glide glide = builder.build(applicationContext);
,查看build方法:
@NonNull
Glide build(@NonNull Context context) {
if (sourceExecutor == null) {
sourceExecutor = GlideExecutor.newSourceExecutor();
}
if (diskCacheExecutor == null) {
diskCacheExecutor = GlideExecutor.newDiskCacheExecutor();
}
if (animationExecutor == null) {
animationExecutor = GlideExecutor.newAnimationExecutor();
}
if (memorySizeCalculator == null) {
memorySizeCalculator = new MemorySizeCalculator.Builder(context).build();
}
if (connectivityMonitorFactory == null) {
connectivityMonitorFactory = new DefaultConnectivityMonitorFactory();
}
if (bitmapPool == null) {
int size = memorySizeCalculator.getBitmapPoolSize();
if (size > 0) {
bitmapPool = new LruBitmapPool(size);
} else {
bitmapPool = new BitmapPoolAdapter();
}
}
if (arrayPool == null) {
arrayPool = new LruArrayPool(memorySizeCalculator.getArrayPoolSizeInBytes());
}
if (memoryCache == null) {
memoryCache = new LruResourceCache(memorySizeCalculator.getMemoryCacheSize());
}
if (diskCacheFactory == null) {
diskCacheFactory = new InternalCacheDiskCacheFactory(context);
}
if (engine == null) {
engine =
new Engine(
memoryCache,
diskCacheFactory,
diskCacheExecutor,
sourceExecutor,
GlideExecutor.newUnlimitedSourceExecutor(),
animationExecutor,
isActiveResourceRetentionAllowed);
}
if (defaultRequestListeners == null) {
defaultRequestListeners = Collections.emptyList();
} else {
defaultRequestListeners = Collections.unmodifiableList(defaultRequestListeners);
}
RequestManagerRetriever requestManagerRetriever =
new RequestManagerRetriever(requestManagerFactory);
return new Glide(
context,
engine,
memoryCache,
bitmapPool,
arrayPool,
requestManagerRetriever,
connectivityMonitorFactory,
logLevel,
defaultRequestOptionsFactory,
defaultTransitionOptions,
defaultRequestListeners,
isLoggingRequestOriginsEnabled,
isImageDecoderEnabledForBitmaps);
}
}
public class LruResourceCache extends LruCache<Key, Resource<?>> implements MemoryCache{...}
这里memoryCache = new LruResourceCache(memorySizeCalculator.getMemoryCacheSize());
就是使用Lru,LruResourceCache继承自LruCache,在LruCache中cache是用LinkedHashMap实现的,accessOrder参数为true,表示允许按访问次数排序。
/** An LRU in memory cache for {@link com.bumptech.glide.load.engine.Resource}s. */
public class LruResourceCache extends LruCache<Key, Resource<?>> implements MemoryCache {...}
**
* A general purpose size limited cache that evicts items using an LRU algorithm. By default every
* item is assumed to have a size of one. Subclasses can override {@link #getSize(Object)}} to
* change the size on a per item basis.
*
* @param <T> The type of the keys.
* @param <Y> The type of the values.
*/
public class LruCache<T, Y> {
private final Map<T, Y> cache = new LinkedHashMap<>(100, 0.75f, true);
...}
从缓存中或者从网络下载得到资源后就调用cb#onResourceReady将资源回传,这里的cb就是callback,SingleRequest对象。
总的来说,内存缓存会尝试从activeResources对象中获取正在使用的资源,如果失败则尝试从cache对象中获取,activeResources是使用弱引用的HashMap,cache是使用Lru算法的LinkedHashMap。
私以为,设计2层内存缓存为了 1:使用弱引用存储正在使用的资源,可以降低内存溢出的风险;因为Lru算法的LinkedHashMap是强引用,会导致内存泄漏;2:在从cache获得资源后,将资源从cache中移除,加入activeResources,减轻了Lru的压力,减少trimToSize的次数。(参考郭霖的Glide缓存机制的评论)
2. 磁盘缓存
磁盘缓存通过diskCacheStrategy方法设置,策略有5种:
- DiskCacheStrategy.ALL
缓存原始数据和处理后的数据,即DATA和RESOURCE的结合 - DiskCacheStrategy.NONE
不缓存任何数据 - DiskCacheStrategy.DATA
缓存获取到的原始未解码数据 - DiskCacheStrategy.RESOURCE
缓存解码后的数据 - DiskCacheStrategy.AUTOMATIC
默认选项,自动判断策略
磁盘缓存使用DiskLruCache实现,实现思路大致和内存缓存一致,针对DiskCacheStrategy.ALL的情况,则是将下载完成的原始数据和解码之后的数据存入缓存。
网友评论