背景
- 工作中,最常使用的就是Glide,因此一直想了解它的内部机制。
- 好早之前看了Glide源码,陷进了源码细节无法自拔,笔记也记了一些比如:“Glide的with方法里,先是封装了RequestManager类,然后封装了xxx类………………”,这些没有意义的流程性的东西。
- 现在站在整体的角度,希望对Glide有一些有用的理解,也功利性的思考:了解它的原理能带给我哪些好处。
图片加载框架
- 首先,要明白Glide是一个图片加载框架;图片加载框架是有一个总体套路的,如图:
* - 也就是说,我们自己也可以通过这个流程实现一个图片框架。
- 那么我们要了解的就是,Glide以及其他开源图片加载框架凭什么就能比我自己写的好?我自己写能不能写的比它好?
Glide
一、缓存
- 图片框架的一般套路是:三级缓存(内存->磁盘->网络)
为什么要三级缓存?答:原则上,不耗费流量的优先,访问速度快的优先。因此,内存既不耗费流量,速度又快,放在第一个获取;磁盘不耗费流量,速度一般,放在第二个;网络既耗费流量,速度又慢,放在最后不得已的时候才进行。
- 不服气:我自己也可以写一个三级缓存,那么我为什么要用Glide?它的缓存凭什么比我的好?
Glide的缓存机制
- Glide是在三级缓存的基础上做了优化:
- 优化一(内存缓存的优化):弱引用缓存正在使用的图片+LruCache
- 一开始有个疑问,弱引用缓存正在使用的图片,为什么不能用强引用缓存?有什么意义呢?
- 答:如果没有弱引用缓存,那么LruCache有可能回收掉正在使用的图片(如果正在使用的图片很多,那么最早存进LruCache的图片为“最近最少使用资源”,会被回收);此时如果再此使用这张图片,会发现内存缓存找不到了,从而跳到磁盘缓存寻找。
- LruCache达到设置的内存大小时,正在使用的图片在LruCache的缓存被回收,此时弱引用缓存存在,因此直接就可以拿来复用,而不用到磁盘缓存了。
- 优化二(磁盘缓存的优化–缓存ImageView大小的图片):
- Glide相比于Picasso,后者会缓存原来大小的图片到内存,前者缓存ImageView大小的图片;
- 因此会导致这些不同:
- Picasso占用内存较大,加载图片较慢(每次加载都要把原图大小裁剪成ImageView大小)
- Glide占用内存小,加载图片快(直接把缓存加载进ImageView即可);但是如果同一张图片加载到不同大小的ImageView,则会重新去网络请求、重新缓存一个新的大小的图片。
- Glide支持设置
DiskCacheStrategy.ALL
缓存策略,既ImageView大小的图片,又缓存原图,内存充足时,推荐使用!
二、Bitmap池
- UIL是一个老图片加载框架了,它基本可以实现一般的加载图片功能,但是它有一个很大的问题:在列表中快速滑动频繁加载图片时会卡顿
- 这是因为快速滑动时,会频繁申请内存用来创建Bitmap对象,也会频繁的销毁Bitmap对象,因而会导致频繁的GC,就造成了内存抖动,阻塞主线程导致了卡顿。
- Glide如何解决的?
- 答:Glide维护了一个Bitmap池来进行Bitmap对象的复用。
三、Bitmap格式
- Picasso默认使用
ARGB_8888
格式的Bitmap;Glide默认使用RGB_565
格式的Bitmap。 -
RGB_565
比ARGB_8888
格式的占用内存小一半,以不支持透明度为代价,只造成了些许失真。 - 总结:如果不使用透明度,则推荐使用
RGB_565
;如果要使用透明度,而且对图片质量要求非常高,则可以用ARGB_8888
;
四、生命周期
- Glide通过with绑定了context的生命周期,如果传入的是Activity或者Fragment,就会在Activity或者Fragment销毁时,销毁页面中使用的图片。
- 如果在某个Activity里,传入的是Application的context,那么就会在应用退出时,才销毁图片。
- 因此,使用时推荐使用Activity或者Fragment的context!
五、Gif图
- Glide、Fresco支持Gif图、Picasso不支持
因此,Glide比Picasso强大
Fresco—最专业,黑科技!
优点
- 5.0以下将图片存到一块特别的内存中,自己进行管理(减少5.0以下手机OOM几率)
- 渐变加载图片:图片从模糊慢慢到清晰(Android系统并不支持,Fresco自己实现的,非常牛逼!)
缺点
- 使用比较复杂
- 需要使用DraweeView替代ImageView