这篇博客其实准备了很久,从Glide的各种使用到Glide的源码分析,Glide的源码很复杂,个人感觉,比LeakCanary,Eventbus等框架源码复杂很多,网上说别Picasso源码复杂,以后再看Picasso的源码吧。
本片博客打算分为三个部分
- Glide的使用以及原理
- Glide的源码分析
- Glide的生命周期
1: Glide的使用
其实关于Glide 的使用,网上有很多,基本都是大同小异,在此不再陈述,这里说一些Glide的比较生疏的用法;
自定义添加动画
当我们第一次加载动画的时候:
private void glideAddAnimation() {
Glide.with(this).load(imageUrl).transition(GenericTransitionOptions.with(R.anim.my_anim)).into(imageView);
}
除了GenericTransitionOptions之外,还有BitmapTransitionOptions和DrawableTransitionOptions,三个的区别不再赘述;R.anim.my_anim也就是我们自己自定义的动画。
上述代码当第一次运行的时候,你会发现挺好的,但是当你第二次运行的时候(相同URL),没有动画过渡;因为上述动画仅仅针对第一次从网络加载图片有效,第二次从缓存获取图片的过渡动画需要另外设置。
Glide.with(this).load(imageUrl)
.transition(GenericTransitionOptions.with(R.anim.my_anim)).listener(
new RequestListener<Drawable>() {
@Override
public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Drawable> target,
boolean isFirstResource) {
return false;
}
@Override
public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target,
DataSource dataSource,
boolean isFirstResource) {
if (dataSource == DataSource.MEMORY_CACHE) {
imageView.startAnimation(
AnimationUtils.loadAnimation(getApplicationContext(), R.anim.my_anim));
}
return false;
}
}).into(imageView);
添加Listener监听,当dataSource代表数据来源,等于MEMORY_CACHE(内存缓存)中获取时,添加动画。
给图片添加动画比较消耗性能,甚至比解码原图资源消耗的都大,所以为了提升性能,请在使用 Glide 向 ListView , GridView, 或 RecyclerView 加载图片时考虑避免使用动画。这是官方的原话。
加载圆角图片
在说圆角图片之前,先说一下,,Glide是支持圆形图片的:
private void glideCircle() {
Glide.with(this).load(imageUrl).apply(RequestOptions.circleCropTransform()).into(imageView);
}
关于圆角图片就需要自定义BitmapTransformation了,代码如下:
/**
* 圆角图片
* Created by ${liumengqiang} on 2018/10/9.
*/
public class SecondRoundTransform extends BitmapTransformation {
private float radius = 10;
@Override
protected Bitmap transform(@NonNull BitmapPool pool, @NonNull Bitmap toTransform, int outWidth, int outHeight) {
//转化后的Bitmap(centerCrop)
Bitmap centerCropBitmap = TransformationUtils.centerCrop(pool, toTransform, outWidth, outHeight);
//从BitmapPool(可以理解为Bitmap池)获取一份Bitmap
Bitmap roundBitmap = pool.get(outWidth, outHeight, Bitmap.Config.ARGB_8888);
//创建画布,在RoundBitmap写入数据
Canvas canvas = new Canvas(roundBitmap);
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setShader(new BitmapShader(centerCropBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP));
RectF rectF = new RectF(0, 0, centerCropBitmap.getWidth(), centerCropBitmap.getHeight());
//圆角
canvas.drawRoundRect(rectF, radius, radius, paint);
return roundBitmap;
}
@Override
public void updateDiskCacheKey(@NonNull MessageDigest messageDigest) {
}
}
private void glideRound() {
Glide.with(this).load(imageUrl).apply(RequestOptions.bitmapTransform(new SecondRoundTransform()))
.into(imageView);
}
在上述自定义BitmapTransformation中,为了防止频繁创建Bitmap造成内存抖动,所以是从BitmapPool中获取Bitmap对象。
官方自定BitmapTransformation 文档:https://github.com/bumptech/glide/wiki/Transformations
缓存策略
关于缓存策略,3.0和4.0差别还是比较大的
Glide3.0
DiskCacheStrategy.NONE:不缓存
DiskCacheStrategy.SOURCE:之缓存原图
DiskCacheStrategy.RESULT:只缓存最终要显示的图片(默认选项; Picasso默认缓存原图)
DiskCacheStrategy.ALL:缓存所有版本的图片
Glide4.0
DiskCacheStrategy.ALL 使用DATA和RESOURCE缓存远程数据,仅使用RESOURCE来缓存本地数据。
DiskCacheStrategy.NONE 不使用磁盘缓存
DiskCacheStrategy.DATA 在资源解码前就将原始数据写入磁盘缓存
DiskCacheStrategy.RESOURCE 在资源解码后将数据写入磁盘缓存,即经过缩放等转换后的图片资源。
DiskCacheStrategy.AUTOMATIC 根据原始图片数据和资源编码策略来自动选择磁盘缓存策略。(默认策略)
关于4.0的默认策略官方是这样说的:
默认的策略叫做 AUTOMATIC ,它会尝试对本地和远程图片使用最佳的策略。当你加载远程数据(比如,从URL下载)时,AUTOMATIC 策略仅会存储未被你的加载过程修改过(比如,变换,裁剪–译者注)的原始数据,因为下载远程数据相比调整磁盘上已经存在的数据要昂贵得多。对于本地数据,AUTOMATIC 策略则会仅存储变换过的缩略图,因为即使你需要再次生成另一个尺寸或类型的图片,取回原始数据也很容易。
Glide加载一张新图片时候会检查多级的缓存:
- 活动资源(ActivityResource):现在是否有另一个ImageView在显示此图片(宽高也一致)
- 内存资源(MemoryCache):图片是否存在在内存中
- 资源类型(Rource):图片是否曾被解码之后写入过磁盘缓存
- 数据来源(Data):原始数据图片是否写入过文件缓存
第一步和第二步检查都是针对于内存的,如果有就直接返回图片。后两步是发生在磁盘上的,需要异步处理。
每个图片都对应一个Key,这个Key的生成参数:图片路径,Transformtion,Options,请求数据类型等参数。
这些参数经过哈希处理之后就生成一个单独的Key。
Glide默认网络请求方式
Glide默认的网络请求实现是:HttpUrlConnection;
添加implementation 'com.github.bumptech.glide:okhttp3-integration:4.3.1’之后默认的加载数据使用时OkHttp。
Glide也支持Volley加载数据,但是其性能要低于OKHttp。
Glide常见需求
- 路径不变,但是服务器的图片变了
- 为了保证图片安全,图片带token加载数据(比如七牛云图片)
- 请求自定义尺寸图片
对于需求1,该问题的产生是由于Glide的缓存机制,Key缓存是根据图片路径以及其它的一些参数决定的,造成的后果就是请求的永远是缓存中的老图片,有同学会说跳过磁盘缓存就行了,这样确实行,Glide的强大之处就在于缓存机制。再次我们提供的思路是在Key上下功夫,思路就是:定期刷新缓存策略或者是key添加标记(例如version版本号)。官网:https://muyangmin.github.io/glide-docs-cn/doc/caching.html
需求2是常见的需求,但是本身项目中没有遇到,所以没有发言权,附上解决方案:https://blog.csdn.net/wangdaqi77/article/details/72819097。
至于这个解决方案原理我们下文讲到。
需求3的场景就是:请求一定尺寸大小的图片。官方解决方案:https://github.com/bumptech/glide/wiki/Do