Glide加载图片流程(Part Two)之缓存流程分析
2016-07-04 19:17
513 查看
承接上文,我们简单了解了Glide加载图片的流程,在这篇博文中,我们就来了解下Glide是如何缓存图片的。
在上篇博文中我们知道,在初始化
代码清单2-1
通过上面的代码,我们可以了解到,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方法中,会通过回调通知
EngineEngineJob 已完成:
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 使用的是二级缓存机制,并引入了引用计数 机制。朋友们可以在阅读源码的过程中慢慢体会其设计的精妙之处。相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories