比较流行的有ImageLoader,Picasso,Fresco,Glide。
1 ImageLoader是很早的图片加载框架,支持图片下载进度的监听,支持View滚动过程中暂停加载。支持多种缓存策略比如最大先删除,最少使用先删除等。
2 Picasso简洁轻量,支持图片缓存使用的监控,支持优先级处理,支持延迟加载,自己不参与本地缓存而是交给OkHttp去实现。
3 Fresco框架较大,使用比较繁琐,支持Gif图片,支持流式显示,类似于网页模糊渐进式显示图片,两个内存缓存和一个Native缓存构建三级缓存。
4 Glide 支持图片缓存,支持Gif,Video。支持优先级处理,与Activity和Fragment生命周期同步,图片默认是RGB_565,质量较差内存更小。功能更为丰富。
项目中用的最多的是Glide:
Glide基本用法with,load,into。
with传入的可以是当前上下文的对象。
load加载图片,图片可以是本地图片,应用资源的图片也可以是一张网络图片。
into传入要展示图片的控件。
with是Glide类的一个静态方法,重载方法很多可以接收
Activity,Fragment,Context。
with方法里面,首先会调用RequestManagerRetriever的静态get方法得到RequestManagerRetriver对象。然后再调用该对象的get方法获取RequestManager对象。静态get方法中也有很多重载方法,主要分为传入Application参数和非Application参数,传入Application参数是最简单的情况,Glide只要持保和整个应用生命周期同步。
非Application参数不管是Activity,Fragment,最终都会向当前Activity传入一个隐藏的Fragment,因为Glide需要监控Activity的生命周期,Fragment依赖Activity生命周期并且是同步的,通过这个隐藏的Fragment就监听到Activity生命周期。
load方法,with方法返回的是一个RequestManager对象,所以load方法在RequestManager类中,load方法也有很多重载,支持本地图片,内存图片,网络图片,只看加载url的load方法。首先调用了fromString方法,再调用load方法,传入图片url,fromString方法里调用了loadGeneric方法,这个方法创建并返回了DrawableTypeRequest对象。
DrawableTypeRequest并没有load方法,load在DrawableTypeRequest的父类DrawableTypeRequestBuildle中。大部分操作都在这个类中,比如placeholder占位符,error,discacheStrategy等。
into方法是Glide图片加载流程中逻辑最为复杂的方法。
into方法在DrawableTypeRequestBuilder类中,里面调用了super.into方法,真正的实现在DrawableTypeRequestBuilder的父类GenericRequestBuilder中,这个类包括了网络请求,图片解析,图片解码,bitmap生成,缓存处理,图片压缩等大量逻辑操作,最后的最后才将图片展示出来。
最关注的是Glide缓存:Glide分为内存缓存和硬盘缓存两个模块,先从内存缓存查找再到硬盘缓存查找最后从网络请求。
每种缓存必须有一个缓存key用来查询,Glide缓存key是在Engine类load方法中实现,通过调用getId方法获取一个字符串id,这个id就是要加载图片的唯一标识。如果是网络图片就是图片的url地址。然后这个id同传入的参数构建出EngineKey也就是Glide的缓存key。
内存缓存:
1 LruCache算法缓存,最近最少使用原则,缓存原理是把最近使用的对象用强引用存储到LinkHashMap中,把最近最少使用的对象在缓存值达到一定上限之前从缓存中移除。
2 弱引用缓存,缓存原理是把正在使用的图片缓存到弱引用的HashMap中,主要防止正在使用的图片被LruCache算法回收。
硬盘缓存:缓存策略有缓存转换后的图片和原始图片,默认是缓存转换后的。缓存算法依然是LruCache是谷歌封装的DisLruCache。
如果有缓存文件的话会调用decodeFromCache从缓存中读取,如果没有调用decodeFromSource,从源头读取比如从网络获取。
遇到Glide缓存问题,项目的图片资源都是放在七牛云上面的,下载下来的图片url地址后面有一个token参数,token作为一个验证身份的参数是时刻变化的。在Glide缓存中是通过图片的url进行缓存的。结果造成了明明是一张图片,因为token的改变导致Glide缓存功能失效。
在查看源码的时候,发现Glide缓存key是在Engine类中load方法中生成的。在这个方法中通过getId()方法返回了一个字符串id,发现这个id就是图片的Url地址。然后找这个getId方法,发现在这个方法里又调用了GlideUrl类中getCacheKey方法,在这个方法里直接返回了图片的url地址,最后通过继承这个GlideUrl类重写getCacheKey方法,去掉图片的Url地址后面的token参数,然后将这个继承类传给Glide的load方法就可以解决Glide缓存问题了。