您的位置:首页 > 移动开发 > Android开发

Glide加载图片流程(Part Two)之缓存流程分析

2016-07-04 19:17 513 查看
承接上文,我们简单了解了Glide加载图片的流程,在这篇博文中,我们就来了解下Glide是如何缓存图片的。

上篇博文中我们知道,在初始化
Glide
对象时,
GlideBuilder
为我们配置了默认的缓存机制:

Glide createGlide() {
if (sourceService == null) {
final int cores = Math.max(1, Runtime.getRuntime().availableProcessors());
sourceService = new FifoPriorityThreadPoolExecutor(cores);
}
if (diskCacheService == null) {
diskCacheService = new FifoPriorityThreadPoolExecutor(1);
}

MemorySizeCalculator calculator = new MemorySizeCalculator(context);
if (bitmapPool == null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
int size = calculator.getBitmapPoolSize();
bitmapPool = new LruBitmapPool(size);
} else {
bitmapPool = new BitmapPoolAdapter();
}
}

if (memoryCache == null) {
memoryCache = new LruResourceCache(calculator.getMemoryCacheSize());
}

if (diskCacheFactory == null) {
diskCacheFactory = new InternalCacheDiskCacheFactory(context);
}

if (engine == null) {
engine = new Engine(memoryCache, diskCacheFactory, diskCacheService, sourceService);
}

if (decodeFormat == null) {
decodeFormat = DecodeFormat.DEFAULT;
}

return new Glide(engine, memoryCache, bitmapPool, context, decodeFormat);
}


代码清单2-1

通过上面的代码,我们可以了解到,Glide 使用了二级缓存机制。接下来我们就从图片的“从无到有”的过程来分析下具体的缓存流程。

一、缓存图片

上篇博文中,我们了解到,我们是在
DecodeJob
decodeSource
方法中拿到图片流资源。紧接着调用其
decodeFromSourceData
方法:

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);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Decoded from source", startTime);
}
}
return decoded;
}


方法中
diskCacheStrategy
是在
GenericRequestBuilder
初始化的,其值默认为
DiskCacheStrategy.RESULT
,即只缓存变换后的图片,而不直接保存原始资源到缓存。故上述方法中并没有保存原始的数据留到缓存中。

那么第一次写入缓存是什么时候呢?我们沿着代码继续往下看,待获取到
decoded
资源后,会在
decodeFromSource
中调用
transformEncodeAndTranscode
方法(不明白调用流程的可参考上篇博文):

private void writeTransformedToCache(Resource<T> transformed) {
if (transformed == null || !diskCacheStrategy.cacheResult()) {
return;
}
long startTime = LogTime.getLogTime();
SourceWriter<Resource<T>> writer = new SourceWriter<Resource<T>>(loadProvider.getEncoder(), transformed);
diskCacheProvider.getDiskCache().put(resultKey, writer);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Wrote transformed from source to cache", startTime);
}
}


transformEncodeAndTranscode
方法中会将变换后的数据流(
Resource<GifBitmapWrapper>
对象)写入磁盘中,并将数据流转码为
GlideBitmapDrawableResource


上篇博文我们知道,在拿到数据对象
GlideBitmapDrawableResource
后,经过一系列的方法调用,会走到
EngineJob
handleResultOnMainThread
方法中。在该方法中,会将我们原来的数据对象包装为
EngineResource
对象。这个对象使用了引用计数 方法对资源进行了控制。当有其他对象方法该资源时会增加计数,反之则减小引用次数。当引用次数减小至0时,则会回调
ResourceListener
onResourceReleased
方法。

同时,在
handleResultOnMainThread
方法中,会通过回调通知
Engine
EngineJob 已完成:

listener.onEngineJobComplete(key, engineResource);


现在我们来看看
Engine
onEngineJobComplete
方法:

@SuppressWarnings("unchecked")
@Override
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()));
}
}
// TODO: should this check that the engine job is still current?
jobs.remove(key);
}


在这个方法中为
EngineResource
设置了回调接口,并在
activeResources
添加了一个资源的若引用。

EngineResource
的引用计数为0时会执行如下方法:

@Override
public void onResourceReleased(Key cacheKey, EngineResource resource) {
Util.assertMainThread();
activeResources.remove(cacheKey);
if (resource.isCacheable()) {
cache.put(cacheKey, resource);
} else {
resourceRecycler.recycle(resource);
}
}


该方法将资源从
activeResources
移除,并放到内存缓存
cache
中。

至此,图片的缓存流程已经分析结束,接下来我们看看缓存的使用。

二、读取缓存

缓存的读取主要发生在
Engine
中的
load
方法中,其读取的顺序依次为Memory cache、
activeResources
表、DiskCache 。相信通过前面的流程分析,读取缓存的流程就很容易了。

三、小结

Glide 使用的是二级缓存机制,并引入了引用计数 机制。朋友们可以在阅读源码的过程中慢慢体会其设计的精妙之处。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Glide Android