Glide 缓存总结(一)
Glide的缓存机制
主要分为2种缓存,一种是内存缓存,一种是磁盘缓存
三级缓存原理
加载一张图片的时候,获取顺序:
Lru算法缓存
【--->】
弱引用缓存
【--->】
磁盘缓存
源码解析如下:
public class Engine implements EngineJobListener,
MemoryCache.ResourceRemovedListener,
EngineResource.ResourceListener {
public <T, Z, R> LoadStatus load(Key signature, int width, int height, DataFetcher<T> fetcher,
DataLoadProvider<T, Z> loadProvider, Transformation<Z> transformation, ResourceTranscoder<Z, R> transcoder,
Priority priority, boolean isMemoryCacheable, DiskCacheStrategy diskCacheStrategy, ResourceCallback cb) {
Util.assertMainThread();
//1.使用 LRU 机制从内存获取,成功则返回,获取不到,下一步
EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
//2.使用弱引用机制从内存获取,成功则返回,获取不到,下一步
EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
//创建一个 runnable 下一步提交给线程池使用,run()方法就是线程池要执行的东东
EngineRunnable runnable = new EngineRunnable(engineJob, decodeJob, priority);
engineJob.start(runnable);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Started new load", startTime, key);
}
return new LoadStatus(cb, engineJob);
}
}
// runnable
class EngineRunnable implements Runnable, Prioritized {
@Override
public void run() {
try {
//执行 decode()方法
resource = decode();
} catch (Exception e) {
//...
}
//...
}
private Resource<?> decode() throws Exception {
if (isDecodingFromCache()) {
//3.从本地缓存获取
return decodeFromCache();
} else {
//4. 从网络请求
return decodeFromSource();
}
}
}
图片存储原理
从网络获取加载图片成功 存储的顺序是:
网络加载
【--->】
磁盘缓存
【--->】
弱引用缓存
【--->】
Lru算法缓存
首先从网络加载图片
若设置缓存原始图片
【1.1】磁盘存储 ,否则跳过这一步
没有设置则
【1.2】存储转换过的图片
【2】图片显示成功,立即放入弱引用缓存
【3】 比如页面退出,则将当前页面的图片数据从弱引用缓存移除,放如LRU缓存
class DecodeJob<A, T, Z> {
private Resource<T> decodeSource() throws Exception {
Resource<T> decoded = null;
try {
// 这是网络请求图片
final A data = fetcher.loadData(priority);
//【1.1】磁盘缓存 这儿是可选的: 存储图片的原始数据,没有处理过的
//下一步1.2】
decoded = decodeFromSourceData(data);
} finally {
}
return decoded;
}
private void writeTransformedToCache(Resource<T> transformed) {
SourceWriter<Resource<T>> writer = new SourceWriter<Resource<T>>(loadProvider.getEncoder(), transformed);
// 【1.2】 磁盘缓存 这是存储转换过的图片数据
//下一步【2】
diskCacheProvider.getDiskCache().put(resultKey, writer);
}
}
public class Engine implements EngineJobListener,
MemoryCache.ResourceRemovedListener,
EngineResource.ResourceListener {
@Override
public void onEngineJobComplete(Key key, EngineResource<?> resource) {
if (resource != null) {
if (resource.isCacheable()) {
//【2】即写入了弱引用 内存缓存
//下一步【3】
activeResources.put(key, new ResourceWeakReference(key, resource, getReferenceQueue()));
}
}
}
//【3】
@Override
public void onResourceReleased(Key cacheKey, EngineResource resource) {
// 步骤1:将缓存图片从弱引用缓存中移除
activeResources.remove(cacheKey);
if (resource.isCacheable()) {
// 步骤2:将该图片缓存放入Lru缓存
cache.put(cacheKey, resource);
}
}
}
弱引用缓存缓存GC回收原理
细心的会发现我们上面使用的弱引用缓存,其实就是一个 hashMap 对象,只要图片加载成功就会放入这个 map 缓存,那么 map里的缓存对象是怎么维护的?
答案就是:
ReferenceQueue+IdleHandler
ReferenceQueue作用:
ReferenceQueue可翻译为引用队列,换言之就是存放引用的队列,保存的是Reference对象。
其作用在于Reference对象所引用的对象被GC回收时,该Reference对象将会被加入引用队列(ReferenceQueue)中
IdleHandler 原理:
略...
在消息队列MessageQueue空闲的时候,会执行IdleHandler,
清除ReferenceQueue中清空ResourceWeakReference对象
public class Engine implements EngineJobListener,
MemoryCache.ResourceRemovedListener,
EngineResource.ResourceListener {
// 这是map 是一个强引用对象
private final Map<Key, WeakReference<EngineResource<?>>> activeResources;
private ReferenceQueue<EngineResource<?>> getReferenceQueue() {
if (resourceReferenceQueue == null) {
resourceReferenceQueue = new ReferenceQueue<EngineResource<?>>();
MessageQueue queue = Looper.myQueue();
queue.addIdleHandler(new RefQueueIdleHandler(activeResources, resourceReferenceQueue));
}
return resourceReferenceQueue;
}
//IdleHandler
private static class RefQueueIdleHandler implements MessageQueue.IdleHandler {
private final Map<Key, WeakReference<EngineResource<?>>> activeResources;
private final ReferenceQueue<EngineResource<?>> queue;
public RefQueueIdleHandler(Map<Key, WeakReference<EngineResource<?>>> activeResources,
ReferenceQueue<EngineResource<?>> queue) {
this.activeResources = activeResources;
this.queue = queue;
}
@Override
public boolean queueIdle() {
//从队列中取出一个元素,队列为空则返回null
//不会空说明ReferenceQueue有被GC回收的ResourceWeakReference对象.
ResourceWeakReference ref = (ResourceWeakReference) queue.poll();
if (ref != null) {
//清空 map 中 被GC回收的ResourceWeakReference对象
activeResources.remove(ref.key);
}
return true;
}
}
}
Glide 用到几个线程池
2个
一个线程池负责从本地获取图片数据
一个线程池负责从网络获取图片数据
class EngineJob implements EngineRunnable.EngineRunnableManager {
private final ExecutorService diskCacheService;
private final ExecutorService sourceService;
}
一张图片加载的流程
Glide 传入 url
【--UI线程->】从内存获取 ,成功则返回
【--本地线程池子线程->】从本地获取,转换的图片数据,成功则返回
【--本地线程池子线程->】从本地获取,原始图片数据,成功则返回
【--网络线程池子线程->】根据 url 网络加载,失败 显示 error 图片
【--网络线程池子线程->】若设置源数据存储 磁盘存储原始图片数据,然后解码, 否则跳过这一步
【--网络线程池子线程->】直接解码
【--网络线程池子线程->】解码图片数据转换,本地存储转换的图片数据,
(所谓转换就是图片处理,缩放,圆角等等操作),使用 handler 切换线程
【--UI线程->】 弱引用缓存存储图片数据
【--UI线程->】 图片显示,动画巴拉巴拉的执行...
其他
IdleHandler 使用
见相关文章
更多内容 欢迎关注公众号
- 2分钟完成30*15页拉勾网职位需求关键词的抓取
- 【专业技术】Linux设备驱动第七篇:高级字符驱动操作之阻塞IO
- Python抓取上海各地区房价平均值
- R语言分析 老九门 到底谁是主角
- 【编程基础】C语言位
- 【专业技术】Android数据保存之文件保存
- 手工创建/删除数据库的步骤
- 用shell帮助解决ORA问题
- 整站40万条房价数据并行抓取,可更换抓取城市
- 大分区表的手工并行优化
- DBMS_STATS收集统计信息的问题及解决
- linux kernel引发的oracle问题及解决
- listener.ora,tnsnames.ora中一个空格的威力
- 【专业技术】Linux设备驱动第六篇:高级字符驱动操作之iotcl
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法