面试问题
- 简单介绍一下Glide缓存
- 具体说说Glide的三级缓存原理
- Glide加载一个100x100的图片,是否会压缩后再加载?放到一个300x300的view上会怎样?
- 简单说一下内存泄漏的场景,如果在一个页面中使用Glide加载了一张图片,图片正在获取中,如果突然关闭页面,这个页面会造成内存泄漏吗?
- Glide跟其他框架相比优势在哪里?
- LruCache算法原理。
简单介绍一下Glide缓存
Glide 缓存机制主要分为2种:内存缓存和磁盘缓存
使用内存缓存的原因是:防止应用重复将图片读入到内存,造成内存资源浪费。
使用磁盘缓存的原因是:防止应用重复从网络或其它地方下载和读取数据。
具体说说Glide的三级缓存原理
Glide的整个缓存流程大概是这样的:
其中 ActiveResource使用弱引用来缓存资源的,防止OOM。
Glide加载一个100x100的图片,是否会压缩后再加载?放到一个300x300的view上会怎样?
当我们调整ImageView大小时,Glide会为每个不同尺寸的ImageView缓存一张图片,也就是说不管你的这张图片有没有被加载过,只要ImageView的尺寸不一样,那么Glide就会重新加载一次,这时候,他会在加载ImageView之前从网络上重新下载,然后再缓存。
举个例子,如果一个页面的ImageView是300 * 300像素,而另一个页面中的ImageView是100 * 100像素,这时候想要让两个ImageView是同一张图片,那么Glide需要下载两次图片,并且缓存两张图片。
public <R> LoadStatus load() {
EngineKey key = keyFactory.buildKey(model, signature,
width, height, resourceClass, transcodeClass, options);
}
从上面代码可以看出,缓存key生成条件之一就是控件的宽高。
简单说一下内存泄漏的场景,如果在一个页面中使用Glide加载了一张图片,图片正在获取中,如果突然关闭页面,这个页面会造成内存泄漏吗?
Glide在加载资源的时候,如果是在Activity,Fragment这一类有生命周期的组件上进行的话,会创建一个透明的RequestManagerFragment加入到FragmentManager之中,感知生命周期,当Activity, Fragment等组件进入不可见,或者已经销毁的时候,Glide会停止加载资源。但是如果是在非生命周期的组件上进行时,会采用Application的生命周期贯穿整个应用,所以applicationManager只有在应用程序关闭时终止加载。
Glide跟其他框架相比优势在哪里?
- 它采用了android原生的HttpURLConnection网络库。
- 支持加载动态图。
- Glide缓存又将它分成了两个模块,一个是内存缓存,一个是硬盘缓存。
- 这两个缓存模块的作用各不相同,内存缓存的主要作用是防止应用重复将 图片数据读取到内存。
- 占用内存小,它默认得编码格式是rgb565。
硬盘缓存:
硬盘缓存的实现也是使用的LruCache算法
当中,而硬盘缓存的主要作用是防止应用重复从网络或其他地方重复下载和读取数据。
调用decodeFromCache()方法从硬盘缓存当中读取图片,一种是调用decodeFromSource()来读取原始图片。默认情况下Glide会优先从缓存当中读取,只有缓存中不存在要读取的图片时,才会去读取原始图片。
调用diskCacheStrategy()方法并传入DiskCacheStrategy.NONE,就可以禁用掉Glide的硬盘缓存功能了。
- DiskCacheStrategy.NONE: 表示不缓存任何内容。
- DiskCacheStrategy.SOURCE: 表示只缓存原始图片。
- DiskCacheStrategy.RESULT: 表示只缓存转换过后的图片(默认选项)。
- DiskCacheStrategy.ALL : 表示既缓存原始图片,也缓存转换过后的图片。
内存缓存:
- Engine类的load()方法当中fetcher.getId()方法获得了一个id字符串,这个字符串也就是我们要加载的图片的唯一标识。
- Glide内存缓存的实现也是使用的LruCache算法。
- loadFromCache()和loadFromActiveResources()。这两个方法中一个使用的就是LruCache算法,另一个使用的就是弱引用。
- skipMemoryCache设置来是否需要内存缓存。
LruCache算法原理
LruCache算法,又称为近期最少使用算法。
LruCache 中 Lru 算法的实现就是通过 LinkedHashMap 来实现的。LinkedHashMap继承于HashMap,它使用了一个双向链表来存储 Map 中的 Entry 顺序关系,对于 get、put、remove 等操作,
LinkedHashMap 除了要做 HashMap 做的事情,还做些调整 Entry 顺序链表的工作。
LruCache 中将 LinkedHashMap 的顺序设置为 LRU 顺序来实现 LRU 缓存,
每次调用 get(也就是从内存缓存中取图片),则将该对象移到链表的尾端。
调用 put 插入新的对象也是存储在链表尾端,这样当内存缓存达到设定的最大值时,将链表头部的对象(近期最少用到的)移除。