Glide
看到一篇文章详细介绍了Glide的源码介绍这里贴出来给大家观看:链接地址
特点:
可以传入activity、fragment,图片的加载会和activity、fragment生命周期一致(比如onPause暂停、onResume重新加载,onDestory销毁)
默认Bitmap格式RGB_565(比ARGB_8888小一半,位图位数越高代表其可以存储的颜色信息越多,当然图像也就越逼真;RGB_565无法显示图片本身的透明度)
Glide加载的大小与imageview一致
可加载gif、WebP
可配置图片动画
体积500 KB
Google推荐
缓存策略:
MemeryCache(LruCache最近最少使用算法)、WeakReference(activeResources弱引用,每次GC会被回收)、DiskCache(磁盘缓存)
LruCache算法解析(为什么内部使用LinkedHashMap)
LruCache内部主要靠一个LinkedHashMap来存储缓存,这里使用LinkedHashMap而不使用普通的HashMap正是看中了它的顺序性,即LinkedHashMap中元素的存储顺序就是我们存入的顺序,而HashMap则无法保证这一点。
我们都知道Lru算法就是最近最少使用的算法,而LruCache是如何保证在缓存大于最大缓存大小之后移除的就是最近最少使用的元素呢?关键在于 trimToSize(int maxSize) 这个方法内部,在它的内部开启了一个循环,遍历LinkedHashMap,删除顶部的(也就是最先添加的)元素,直到当前缓存大小小于最大缓存,或LinkedHashMap为空。这里需要注意的是由于LinkedHashMap的特点,它的存储顺序就是存放的顺序,所以位于顶部的元素就是最近最少使用的元素,正是由于这个特点,从而实现了当缓存不足时优先删除最近最少使用的元素。
加载过程:
正在使用中的图片使用弱引用activeResources来进行缓存,不在使用中的图片使用LruCache来进行缓存;
activeResources保证正在使用的图片不被Lru算法回收。
如果要使用图片,首先从LruCache取出图片,然后存到activeResources,图片释放的时候,再把图片存到LruCache。这样在使用LRU算法的时候,正在使用的图片在弱引用里,就不会被回收。
硬盘缓存,默认情况下在硬盘缓存的就是转换过后的图片
缓存处理关键类:LruResourceCache、DiskCache
Fresco
特点:
SimpleDraweeView
- 图像的渐进式呈现
- 体积太大2~3M
- 也可加载gif、webP
- 5.0以下系统,把bitmap保存到ashmen(匿名共享内存机制),不会启动gc,使的界面不会因为gc而卡死,
- Facebook主导
缓存策略:
Fresco使用三级缓存,已解码内存缓存;未解码内存缓存;磁盘缓存
第一级缓存就是保存bitmap,直接存的就是bitmap对象,5.0 以下,这些位于ashmem,5.0以上,直接位于java的heap上
第二级缓存保存在内存,但是没有解码,使用时需要解码,
第三级缓存就是保存在本地文件,同样文件也未解码,使用的时候要先解码啦!
在5.0以下,GC将会显著地引发界面卡顿。Fresco将图片放到一个特别的内存区域。当然,在图片不显示的时候,占用的内存会自动被释放。这会使得APP更加流畅,减少因图片内存占用而引发的OOM。
3级缓存加载机制,按照优先级逐级命中并返回:
1)找Bitmap cache中是否有图片,有则加载,否则接着找;
2)再看Encoded Memory中是否有图片,有则decode,transform 后加载图片,并将图片存储进Bitmap Cache,找不到则接着往下找;
3)下一步看Disk Cache(官网有对这个命名的解释,看完大家都明白了:Yes, we know phones don’t have disks, but it’s too tedious to keep saying local storage cache),有则decode,transform 后加载图片,并将图片存储进Bitmap Cache,Encoded Memory中,找不到则接着往下找;
4)最后就是终极network cache寻找,有则decode,transform 后加载图片,并将图片存储进Bitmap Cache ,Encoded Memory, Disk Cache,当然如果没有就直接加载失败了。
3种线程池处理相关操作:
1) 3个线程用于网络下载。
2) 两个线程用于磁盘操作: 本地文件的读取,磁盘缓存操作。
3)两个线程用于CPU相关的操作: 解码,转换,以及后处理等后台操作
加载图片的流程:
查找Bitmap缓存中是否存在,存在则直接返回Bitmap直接使用,不存在则查找未解码图片的缓存,如果存在则进行Decode成Bitmap然后直接使用并加入Bitmap缓存中,如果未解码图片缓存中查找不到,则进行硬盘缓存的检查,如有,则进行IO、转化、解码等一系列操作,最后成Bitmap供我们直接使用,并把未解码(Encode)的图片加入未解码图片缓存,把Bitmap加入Bitmap缓存中,如硬盘缓存中没有,则进行Network操作下载图片,然后加入到各个缓存中。
源码缓存处理位置:
com.facebook.imagepipeline.core.ImagePipelineFactory初始化com.facebook.imagepipeline.core.ImagePipeline.java
ImagePipeline负责图片的获取和管理。图片可以来自远程服务器,本地文件,或者Content Provider,本地资源。压缩后的文件缓存在本地存储中,Bitmap数据缓存在内存中。
在5.0系统以下,Image Pipeline 使用 pinned purgeables 将Bitmap数据避开Java堆内存,存在ashmem中。这要求图片不使用时,要显式地释放内存。
SimpleDraweeView自动处理了这个释放过程,所以没有特殊情况,尽量使用SimpleDraweeView,在特殊的场合,如果有需要,也可以直接控制Image Pipeline。
我们可以通过imagepipeline判断bitmap是否被缓存,
ImagePipeline imagePipeline = Fresco.getImagePipeline();
imagePipeline.isInBitmapMemoryCache(Uri.parse(""));
imagePipeline.isInDiskCache(Uri.parse("xxx"));
删除指定缓存
Uri uri = Uri.parse("xxx");
imagePipeline.evictFromCache(uri);
imagePipeline.evictFromDiskCache(uri);
想看源码的同学可以参考这篇博客:
Glide:https://www.jianshu.com/p/57123450a9c8
Fresco: https://www.jianshu.com/p/1bb97abcd126