最近项目用Glide来加载图片,也遇到了一些问题,这里记录总结下。Demo代码点这里
一、Glide简单使用
Glide的Github地址这里,使用比较简单,直接在Gradle里引入
compile 'com.github.bumptech.glide:glide:3.7.0'
最简单的使用,这四个也是最基础必备的
Glide.with(this).load(url).into(imageView);
正常来说还要有占位图,错误图,大小,缓存啊等等一系列配置,都可以像上面一样一条链自由组合,简单说下Glide的一些常用方法。
1.with()
with提供了几种构造方法,可以在源码里看,有Context, Activity, Fragment等,如果传入Application.this作为参数时,Glide的加载不受当前Activity生命周期影响,但这会导致即使Activity结束后,仍然继续加载图片。
2.load()
load可以加载网络图片链接,也可以加载本地图片地址,以及resourceId, File等等
3.into()
into直接传入ImageView;
4.placeholder()
在加载过程中设置占位图,可以传入Drawable或resouceId
5.error()
加载失败显示的图片,可以传入Drawable或resouceId
6.override(int width, int height)
设置加载图片的宽高,像素为单位,在自定义ImageView大小或者计算瀑布流高度时,偶尔会用到。
7.dontAnimate()
Glide加载时默认会有淡入淡出的加载效果,该方法可以去掉动画效果,直接显示图片
8..skipMemoryCache(true)
跳过图片缓存
9.diskCacheStrategy(DiskCacheStrategy.ALL)
设置缓存策略,可选的参数有 :ALL(缓存所有数据), NONE(不缓存), SOURCE(只缓存源数据), RESULT(只缓存转换后的数据);
10.priority(Priority.NORMAL)
加载优先级,优先级越高越先加载
11.crossFade(int duration)
加载时淡入淡出动画时间,也可以不传,默认300ms
12.animate()
自定义加载动画
13.thumbnail(0.1f)
设置缩略图,先加载缩略图再加载完整图片,在大量的图片流列表里,这个方法还是挺好用的, 快速滑动列表时,不致于出现大量的空白.
14.asBitmap()
把图片当成bitmap对待,如果是Gif时会停留在第一帧
15.asGif()
加载GIF图片,不加该方法时,也可以加载GIF;加了该方法,如果资源不是GIF,会加载失败。
16.bitmapTransform()
对图片进行转换,只能用于bitmap
17.transform()
对图片进行转换
16.Glide.get(this).clearDiskCache()
清理磁盘缓存,需要在子线程中执行
17.Glide.get(this).clearMemory();
清理内存缓存,可以直接在主线程执行
二、遇到的一些问题
1. 圆形图片设置占位图后第一次只显示占位图,第二次才正常显示
这个问题比较多出现在用了自定义的圆形图片控件或者CircleImageView之类的,解决方法如下:
(1)不设置占位图
(2)使用Glide自带的转换来加载圆形图片
Glide.with(this)
.load(url)
.asBitmap()
.centerCrop()
.override(300, 300)
.error(R.mipmap.delete)
.into(new BitmapImageViewTarget(imageView) {
@Override
protected void setResource(Bitmap resource) {
RoundedBitmapDrawable circularBitmapDrawable =
RoundedBitmapDrawableFactory.create(context.getResources(), resource);
circularBitmapDrawable.setCircular(true);
imageView.setImageDrawable(circularBitmapDrawable);
}
});
(3) 使用bitmap加载到CircleImageView中
Glide.with(mContext)
.load(url)
.placeholder(R.drawable.loading_spinner)
.into(new SimpleTarget<Bitmap>(width, height) {
@Override
public void onResourceReady(Bitmap bitmap, GlideAnimation anim) {
CircleImageView使用setImageBitmap(bitmap)
}
};
2.设置了占位图后,第一次加载的图片大小和占位图一样
比如我在XML里这么写
<ImageView
android:id="@+id/normal_iv"
android:layout_width="150dp"
android:layout_height="200dp"
android:scaleType="fitCenter"/>
在Activity里这么写
Glide.with(mContext)
.load(Constant.IMAGE_URL)
.placeholder(R.mipmap.ic_zhanwei)
.into(normalIv);
占位图是一张正方形的图,要加载的是一张宽图,ScaleType用的是fitCenter,理论上讲加载出来的图片应该是居中等比例显示的,就像这样
但实际上第一次加载时,是这样
图片被拉伸到和占位图一样的大小, 只有加载过一次后,图片才能正常加载。这种情况比较多出现在特定宽高或者动态创建ImageView时,设置的占位图和实际加载的图片或ScaleType比例不同,解决办法是去除占位图,在ImageView中设置background当占位图。
3.You cannot start a load for a destroyed activity
当Glide.with()传的是Activity或者Fragment的Context时,比较容易出现这个报错。这是由于Activity已经destroy了,但是Glide依然在加载图片,结果就报错了。
比较常见的解决办法是传入ApplicationContext, 这样虽然不会出问题,但当Activity已经关闭时,还会继续加载,有点浪费内存了。 这个issue 提到说如果是在async task使用Glide加载时,最好还是传入ApplicationContext, 尽量避免新开线程去加载图片。
个人使用的方法有两个:
方法一: 项目一般都会写一个统一的图片加载工具,图片加载最后都通过统一的一个方法,当activity 销毁后,使用Glide加载会报错,那就可以在加载方法的最开始添加一个判断,如果当Activity已经销毁时,就return, 不进行加载,反之再进入加载代码,如下:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
if (context instanceof Activity && ((Activity) context).isDestroyed()) {
return;
}
}
这样加了一个判断后,没有遇到过报错了,目前来看还是可行的。
方法二: 目前项目用到的方法是使用RequestManager来替代Glide.with, 也就是说,在统一的加载方法中定义的是RequestManager, 然后使用时传入Glide.with(context)。RequestManager可以同步Activity/Fragment的生命周期,当Activity销毁时,Glide的加载也会停止,使用起来也是很方便,代码如下:
统一的加载方法, LoadOption是我自己定义的加载选项,可以忽略:
private void initLoadImage(RequestManager glide, Context context, String url, ImageView imageView, LoadOption option) {
glide.load(url)
.error(R.mipmap.delete)
.thumbnail(0.1f)
.into(imageView);
}
使用时直接传入Glide.with(context)
initLoadImage(Glide.with(context), context, url, imageView, LOAD_ORIGIN);
也可以参考下这个问题。在我的Demo里也简单封装了一个Glide工具类,有问题的可以看看。
4.加载GIF特别慢或加载出错
偶尔需要加载GIF图片时,会出现加载很慢的情况,可以加上diskCacheStrategy(DiskCacheStrategy.SOURCE),这样可以很快加载出来。另外可以通过GlideDrawableImageViewTarget(ImageView view, int maxLoopCount)进行循环次数的控制。
加载GIF一般会加上asGif的方法,不加也是可以加载的,但如果加上这个方法后,图片却不是GIF,会加载出错。
三、Glide加载不同类型图片,如圆形,圆角,毛玻璃等
之前在加载圆形头像有说到可以在into的方法里new一个SimpleTarget或者BitmapImageViewTarget取得图片bitmap,最后自行处理,但对于链式结构的Glide加载代码而言,这么写看着有些冗杂。Glide也提供了bitmapTransform和transform的方法,可以自定义转换Transformation。
这里推荐一个强大的转换库Glide Transformations,支持圆形,圆角,毛玻璃,滤镜等等一系列加载转换,基本都是一行代码实现,可以满足绝大多数的需求了。
用法
直接在gradle里导入
compile 'jp.wasabeef:glide-transformations:2.0.2'
简单使用时
Glide.with(this).load(R.drawable.demo)
.bitmapTransform(new BlurTransformation(context))
.into((ImageView) findViewById(R.id.image));
混合使用:
Glide.with(this).load(R.drawable.demo)
.bitmapTransform(new BlurTransformation(context, 25), new CropCircleTransformation(context))
.into((ImageView) findViewById(R.id.image));
使用相当方便,具体可以到GitHub上看看。
暂时到这,如果有发现新的问题再继续补充。