glide之总结2
1、图片库对比
一. 如何缓存动态Url的图片?
一般情况下我们从网络上获取到的图片Url都是静态的,即一张图片对应一个Url。那么如果是一张图片对应多个Url呢?缓存不就没有意义了。
因为图片加载库都是拿图片的Url来作为缓存的key的,Glide也不例外,只是会更加复杂一些。如果你开启了Glide的log,就会在控制台看到Glide是如何指定缓存key的。关于如何打开log,请参考这篇文章。
一般来说,Glide的key由图片的url、view的宽和高、屏幕的尺寸大小和signature组成。在什么情况下才会出现动态的Url呢?
一个很典型的例子就是因为图片的安全问题在原来图片的Url后面加上访问凭证。访问凭证与时间关联,这样一来,在不同时间同一图片的Url就会不同,缓存就会失效。以七牛的私有空间为例,我们来看看如何去缓存这类图片。从七牛关于私有空间的文档中可以得到:最终的Url = 原Url + ?e=过期时间 + token=下载凭证。
那么就只需要在Glide缓存时将Url中“?”后面的字符串截去就可以了。
首先新建一个叫做QiNiuImage的类:
public class QiNiuImage {
private final String imageUrl;
public QiNiuImage(String imageUrl) {
this.imageUrl = imageUrl;
}
public String getImageUrl() {
return imageUrl;
}
public String getImageId() {
if (imageUrl.contains("?")) {
return imageUrl.substring(0, imageUrl.lastIndexOf("?"));
} else {
return imageUrl;
}
}
}
其中getImageUrl方法返回真实的Url,getImageId方法返回未添加下载凭证前的Url。
然后再自定义一个实现ModelLoader接口的QiNiuImageLoader:
public class QiNiuImageLoader implements StreamModelLoader<QiNiuImage> {
@Override
public DataFetcher<InputStream> getResourceFetcher(final QiNiuImage model, int width, int height){
return new HttpUrlFetcher(new GlideUrl(model.getImageUrl())) {
@Override
public String getId() {
return model.getImageId();}
};
}
public static class Factory implements ModelLoaderFactory<QiNiuImage, InputStream> {
@Override
public ModelLoader<QiNiuImage, InputStream> build(Context context,
GenericLoaderFactory factories) {
return new QiNiuImageLoader();
}
@Override
public void teardown() { /* no op */ }
}
其中HttpUrlFetcher的getId方法就是组成缓存的key的重要部分。这也是我们的核心原理。
将这个ModelLoader注册到GlideModule中,并在AndroidManifest.xml中注册:
public class QiNiuModule implements GlideModule {
@Override
public void applyOptions(Context context, GlideBuilder builder) {
}
@Override
public void registerComponents(Context context, Glide glide) {
glide.register(QiNiuImage.class, InputStream.class, new QiNiuImageLoader.Factory());
}
}
<meta-data
android:name="com.yourpackagename.QiNiuModule"
android:value="GlideModule"/>
最后只需要在加载此类图片时,使用下面这段代码就可以了。即使图片的token更换了也不会重新从网络上下载而是直接读取本地缓存。
Glide.with(context).load(new QiNiuImage(imageUrl).into(imageView);
二. 图片库对比
1) Glide Google 开源
支持 Gif WebP Video
生命周期继承
高效缓存策略
- 支持Memory和Disk缓存
- Picasso 只会缓存原始尺寸图片,而Glide缓存时多种规格
- 内存开销小,默认 RGB_565,Picasso 默认是 ARGB_8888
缺点:
- 使用方法复杂,实现方法较多
- 使用比Fresco简单,但性能(加载&缓存)却比不上 Fresco
Picasso Glide Fresco比较?
2) Picasso 毕加索 Square
Picasso 没有实现本地缓存功能,交给了Square 的另外一个网络库okhttp去实现。
好处是可以通过请求 Response Header 中的 Cache-Control及Expired 控制图片的过期时间。
- 使用简单,代码简洁
- 与Square其他类库搭配兼容性好,Retrofit OkHttp 等
缺点:
- 功能简单 图片加载
- 性能(加载速度等等)较(Glide、Fresco)差
- 自身没有实现"本地缓存"
3) Fresco Facebook
- 大大减少OOM,底层使用C++技术解决图片缓存问题
- 使用加单,几乎全部功能都能在 xml 上定制
缺点:
- 用法变得更加复杂
- 依赖包更大了 2~3M
- 底层C++,阅读源码困难
对比项 | Picasso | Glide | Fresco |
---|---|---|---|
地址 | github.com/square/pica… | github.com/bumptech/gl… | github.com/facebook/fr… |
发布时间 | 2013年5月 | 2014年9月 | 2015年5月 |
是否支持gif | false | true | true |
是否支持webP | true | true | true |
视频缩略图 | false | true | true |
大小 | 100k | 500 KB | 2~3M |
加载速度 | 中 | 高 | 高 |
Disk+Men Cache | true | true | true |
Easy of use | low | mediun | difficult |
star | 13160 | 14709 | 12444 |
开发者 | Square主导 | Google主导 | Facebook主导 |
详细属性对比
对比项 | Glide | Fresco |
---|---|---|
配置 | compile 'com.github.bumptech.glide:glide:XXX.XXX' | compile 'com.facebook.fresco:fresco:XXX.XXX |
初始化 | 直接使用 | Fresco.initialize(this); |
layout | 普通ImageView | 独有的SimpleDraweeView |
圆角, 圆形 | 需要自己实现圆角,继承自BitmapTransformation操作bitmap对象实现 | 通过RoundingParams设置参数 |
缓存 | Glide内存和磁盘缓存 | 三级缓存,分别是 Bitmap缓存,未解码图片缓存, 文件缓存。 |
缓存图像大小 | Glide则会根据ImageView控件尺寸获得对应的大小的bitmap来展示,从而缓存也可以针对不同的对象:原始图像(source),结果图像(result) | 缓存原始图像 |
加载策略 | Glide只有占位图 | 先加载小尺寸图片,再加载大尺寸的 |
加载进度 | false | true |
Bitmap myBitmap = Glide.with(上下文)
.load(url)
.asBitmap() //必须
.get()
//同样在DataSubscriber中获取
FileBinaryResource resource = (FileBinaryResource) Fresco.getImagePipelineFactory().getMainFileCache().getResource(new SimpleCacheKey(url));
if (resource != null && resource.getFile() != null) {
setImage(ImageSource.uri(Uri.fromFile(resource.getFile())));
}
三. Fresco 源码分析
初始化Fresco。
获取DataSource。
绑定Controller与Hierarchy。
从内存缓存/磁盘缓存/网络获取图片,并设置到对应的Drawable层。
缓冲缓存层:由BufferedDiskCache实现,提供缓冲功能。
文件缓存层:由DiskStorageCache实现,提供实际的缓存功能。
文件存储层:由DefaultDiskStorage实现,提供磁盘文件读写的功能。
DiskStorageCache:实现了FileCache接口与DiskTrimmable接口是缓存的主要实现类。
DefaultDiskStorage:实现了DiskStorage接口,封装了磁盘IO的读写逻辑。
BufferedDiskCache:在DiskStorageCache的基础上提供了Buffer功能。
private static final String CONTENT_FILE_EXTENSION = ".cnt"; private static final String TEMP_FILE_EXTENSION = ".tmp";
未解码图片内存缓存:由EncodedImage描述真正的缓存对象。 已解码图片内存缓存:由BitmapMemoryCache描述真正的缓存对象。
作者:爱雨浮龙
链接:https://juejin.cn/post/6844904005450104839