1、生命周期管理
通过创建一个无UI的fragment来感应页面的生命周期
2、缓存实现
Glide使用了ActiveResources(活动缓存弱引用)+MemoryCache(内存缓存Lru算法)+DiskCache(磁盘缓存Lru算法)。
ActiveResources:存储当前界面使用到的图片。界面不展示后,该Bitmap又被缓存至MemoryCache中,并从ActiveResources中删除。
Memory Cache:存储当前没有使用到的Bitmap,当Bitmap被使用后,该Bitmap又被缓存至ActiveResources中,并从MemoryCache中删除。
Disk Cache:持久缓存。例如图片加圆角,处理后图片会被缓存到文件中,应用被再次打开时可以加载缓存直接使用。
注意:ActiveResources + MemoryCache是内存缓存,都属于运行时缓存,且互斥(同一张图片不会同时缓存在ActiveResources+MemoryCache),应用被杀死后将不存在。
LruCache实现原理
利用了LinkedHashMap排序方式的特性:由于使用访问顺序排序,进行了get/put操作的元素会放在Map最后面。所以当最后一个元素插入进来时,如果当前的缓存数据大小超过了最大限制,那么会删除Map中放在前面的元素。
Map cache =newLinkedHashMap<>(100,0.75f,true):
其中第二个参数0.75f表示加载因子,即容量达到75%的时候会把内存临时增加一倍。
最后这个参数也至关重要,表示访问元素的排序方式,true表示按照访问顺序排序,false表示按插入的顺序排序。
Glide缓存Key
缓存是为了解决重复加载问题,那必然要有一个key来区分不同的图片资源。从下面生成key的代码可以看出Glide生成key的方式远比我们想象的要复杂,决定缓存Key的参数有8种,其中包括图片URL、宽、高。
#Engine.load()//生成缓存keyEngineKeykey=keyFactory.buildKey(model,signature,width,height,transformations,resourceClass,transcodeClass,options);
这里可以得出一个结论,几乎任意配置的改变都会导致同一张图片生成多个缓存key。举个例子:同一张图片加载到2个不同大小的ImageView会生成2个缓存图片。
总结:
Glide缓存分为弱引用+ LruCache+ DiskLruCache,其中读取数据的顺序是:弱引用 > LruCache > DiskLruCache>网络;写入缓存的顺序是:网络 --> DiskLruCache-->弱引用-->LruCache
内存缓存分为弱引用的和 LruCache ,其中正在使用的图片使用弱引用缓存,暂时不使用的图片用 LruCache缓存,这一点是通过 图片引用计数器(acquired变量)来实现的
磁盘缓存就是通过DiskLruCache实现的,根据缓存策略的不同会获取到不同类型的缓存图片。它的逻辑是:先从转换后的缓存中取;没有的话再从原始的(没有转换过的)缓存中拿数据;再没有的话就从网络加载图片数据,获取到数据之后,再依次缓存到磁盘和弱引用。
问题:
为什么Glide内存缓存要设计2层,弱引用和LruCache?
比较靠谱的回答:
使用一个弱引用map activeResources来盛放项目中正在使用的资源。Lrucache中不含有正在使用的资源。资源内部有个计数器来显示自己是不是还有被引用的情况,把正在使用的资源和没有被使用的资源分开有什么好处呢??因为当Lrucache需要移除一个缓存时,会调用resource.recycle()方法。注意到该方法上面注释写着只有没有任何consumer引用该资源的时候才可以调用这个方法。那么为什么调用resource.recycle()方法需要保证该资源没有任何consumer引用呢?glide中resource定义的recycle()要做的事情是把这个不用的资源(假设是bitmap或drawable)放到bitmapPool中。bitmapPool是一个bitmap回收再利用的库,在做transform的时候会从这个bitmapPool中拿一个bitmap进行再利用。这样就避免了重新创建bitmap,减少了内存的开支。而既然bitmapPool中的bitmap会被重复利用,那么肯定要保证回收该资源的时候(即调用资源的recycle()时),要保证该资源真的没有外界引用了。这也是为什么glide花费那么多逻辑来保证Lrucache中的资源没有外界引用的原因。
1、避免正在使用的图片被回收/
2、分压策略,减少Lrucache 中trimToSize的概率。如果正在remove的是张大图,lrucache正好处在临界点,此时remove操作,将延缓Lrucache的trimToSize操作;
3、提高效率:弱引用用的是HashMap,Lrucache用的是LinkedHashMap,从访问效率而言,肯定是HashMap更高。