Glide使用中的踩坑和填坑

在使用Glide的过程中,遇到不少问题,如下:

  1. 加载本地国际化图片资源时出现错乱。
  2. 加载Gif图时显示奇慢。
  3. Glide加载图片的ImageView不能设置tag。
  4. 使用CircleImageView时图片显示不正常。

本文,对遇到的这些问题进行了分析和总结。

Glide是Google的一个图片加载的优秀开源库。其几大特点:

  1. 通过with()参数传入Activity/Fragment,实现图片加载和Activity/Fragment的生命周期联动,即onPause即停止加载,onResume继续下载。
  2. 专门针对列表加载进行了优化,不用担心复用convertView引起图片错位问题的出现。
  3. 支持gif图,支持gif图,不用再额外添加gif的支持库。
  4. 图片质量。图片质量参数默认采用2bytes/pixel的Bitmap.Config.RGB_565,如果对图片质量要求高,可通过自定义GlideModule来实现4bytes/pixel高质量的ARGB_8888。
  5. 智能的内存开销优化。Glide每次加载都会自动计算出ImageView的大小和所需要的显示尺寸,而不是将全尺寸的图片加载至内存,优化内存占用。
  6. 智能的磁盘缓存,加载显示快。Picasso每次加载都是全尺寸的图片,所有在列表快速滑动时,加载速度会较慢;但是Glide可以设置磁盘缓存策略DiskCacheStrategy.ALL,即缓存全尺寸又缓存其他尺寸,使得列表中快速回滚时图片可以迅速加载显示。
  7. 可以直接加载本地资源图片,比直接设置src更省内存。
  8. 链式调用,简单到没有学习成本。
  9. 库体积小啊。

为啥不用其他的图片加载开源库呢?

  • Fresco. 很牛逼,加载据说是最快的,但是体积太大。
  • Picasso. 内存占用大,加载较慢。
  • UImageLoader. 配置参数多多。
    但是…..他们都不支持Gif啊,还是选我大Glide吧,而且Glide在绝大多数应用场景中已经够用和优秀。

下面就说说在项目实际使用中遇到的一些坑,和对应的解决方案,正文开始。

踩坑与填坑

Glide加载本地国际化图片资源时出现错乱


为了批量加载大图片避免oom,采用Glide加载本地图片资源,但是在切换应用语言时,对应的国际化的图片资源却没自动切换。纳尼?莫非Glide不支持国际化资源加载,不可能啊,在不同语言下刚安装第一进入时加载都是正确的呀!哪个地方出问题了呢?

分析
经过分析测试,把问题定位在磁盘缓存上。Glide在不设置DiskCacheStrategy时默认采用DiskCacheStrategy.RESULT的缓存策略,即存储此次加载的结果,那么,在切换语言时,再次加载图片时,默认是从缓存中读取的,而不是新的资源路径,那么就会造成这次加载的和上次加载的一样,结果就是,切换了语言环境,但是图片资源无变化。

解决方案
只需修改其磁盘缓存策略即可,不做磁盘缓存,即设置磁盘缓存策略为NONE,代码实现为:

1
Glide.with(context).*.*.diskCacheStrategy(DiskCacheStrategy.NONE).into(imageView);

建议:使用Glide加载本地图片时最好将磁盘缓存策略设置为NONE,首先,既然是本地资源,根本无需再做本地缓存了,其次避免出现类似国际化资源出现的问题。

Glide加载Gif图片时显示奇慢

坑:
在利用Glide加载Gif图片时,采用和加载.png/.jpg一样的调用方式时,发现Gif图的加载速度超级慢啊,而应用中Gif图有时会有连续的好几张,这时就一直loading,真烦人。

分析:
在搜索后,准备到Glide下提个issue,发现已经有人提过,而且作者也给出了解决方案,加载Gif时除了调用asGif()方法外,还需特别设置缓存策略(又是缓存策略的问题,可见这块是个烦人的点啊),需要将缓存策略设置为SOURCE或者NONE,即设置为缓存原图资源或者不做缓存。猜想是,在做ALL或者RESULT的缓存策略时,需要转换处理Gif图,造成较耗资源,显示缓慢。

解决方案:
三点:asGIf(), DiskCacheStrategy.SOURCE/NONE, dontAnimate(), dontAnimate()为个人建议,实测中发现去掉动画会显示更快。
在实际项目中可以这样写:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
if(picUrl.endsWith(".gif")){
Glide.with(resultFragment)
.load(picUrl)
.asGif()
.override(width,height)
.placeholder(placeholderImg)
.error(errorImg)
.dontAnimate()
.centerCrop()
.diskCacheStrategy(DiskCacheStrategy.SOURCE)// DiskCacheStrategy.NONE
.into(ivPic);
}else{
Glide.with(resultFragment)
.load(picUrl)
.override(width,height)
.placeholder(placeholderImg)
.error(errorImg)
.crossFade()
.centerCrop()
.into(ivPic);
}

Glide加载的ImageView设置tag就报错

坑:
利用Glide加载图片的ImageView,在给其设置tag时会出现报错:Java.lang.IllegalArgumentException: You must not call setTag() on a view Glide is targeting 。这是因为Glide为了防止在列表中出现的错乱情况,默认给Glide加载的对象(ImageView)设置了tag,就像我们早期使用图片加载时自己手动做的tag处理防止图片加载错位。
解决方案:
以下三种方案,参考自博文Glide 一个专注于平滑滚动的图片加载和缓存库
方案一:
最简单方便,使用setTag(int,object)方法设置tag。

方案二:
(1) 先实现GlideMoudle接口,全局设置ViewTaget的tagId

1
2
3
4
5
6
7
8
9
10
11
public class MyGlideMoudle implements GlideModule{
@Override
public void applyOptions(Context context, GlideBuilder builder) {
ViewTarget.setTagId(R.id.glide_tag_id);
}
@Override
public void registerComponents(Context context, Glide glide) {
}
}

(2) 在ids.xml下添加id

1
<item name="glide_tag_id" type="id"/>

(3) 在AndroidManifest.xml文件里面添加

1
2
3
<meta-data
android:name="com.yourpackagename.MyGlideMoudle"
android:value="GlideModule" />

方案三:
写一个继承自ImageViewTaget的类,复写它的get/setRequest方法。具体实现参考博文,再次不再贴出。

使用CircleImageView加载图片时显示不正常


在使用CircleImageView实现圆形头像时,如果Glide设置了placeHolder,加载时会出现加载不出图片的情况。

分析:
CircleImageView引起的与占位图和显示动画的冲突问题。

解决方案:
方案一: 不设置placeholder占位图。
方案二: 使用Glide的Transformation自己设置圆形图片,具体参考这个How do rounded image with Glide library?
方案三: 去掉Glide加载的默认动画,即调用dontAnimate()方法。

延伸阅读

  1. Introduction to Glide
  2. Google推荐的图片加载库Glide介绍
  3. Glide 一个专注于平滑滚动的图片加载和缓存库
文章目录
  1. 1. 踩坑与填坑
    1. 1.1. Glide加载本地国际化图片资源时出现错乱
    2. 1.2. Glide加载Gif图片时显示奇慢
    3. 1.3. Glide加载的ImageView设置tag就报错
    4. 1.4. 使用CircleImageView加载图片时显示不正常
  • 延伸阅读
  • ,