一、引言
现在Android上的图片加载框架非常成熟,从最早的老牌图片加载框架UniversalImageLoader,到后来Google推出的Volley,再到后来的新兴军Glide和Picasso,当然还有Facebook的Fresco。每一个都非常稳定,功能也都十分强大。作为开发人员,虽然它们的使用场景有重合,但还是有必要去了解每个框架的基本功能及使用方法。
对于Glide这个加载图片的框架,很多人都在用,我之前使用的是UIL,近两年也有在用Glide和Fresco,但Gilde是Google推荐的加载图片框架,功能非常强大,而且还有Google专人维护,所以有必要整理一下Glide的使用。
二、Glide介绍
在泰国举行的谷歌开发者论坛上,谷歌为我们介绍了一个名叫 Glide 的图片加载库,作者是bumptech。这个库被广泛的运用在google的开源项目中,包括2015年google I/O大会上发布的官方APP。
Glide是一个快速高效的Android图片加载库,注重于平滑的滚动。Glide提供了易用的API,高性能、可扩展的图片解码管道(decode pipeline),以及自动的资源池技术。Glide 支持拉取,解码和展示视频快照,图片,和GIF动画。Glide的API很灵活,开发者可以插入和替换成自己喜爱的任何网络栈。默认情况下,Glide使用的是一个定制化的基于HttpUrlConnection的栈,但同时也提供了与Google Volley和Square OkHttp快速集成的工具库。
Glide是谷歌为我们推荐的一个图片加载库。为什么要选择使用Glide呢?
- 代码有人维护,不至于出现问题,项目组都搞不定的时候问题无法解决(ImageLoader已没人维护了)
- 代码简洁,可读性很好(Fresco是一个非常优秀的库,但是配置稍显麻烦,同时代码风格读起来有些生疏)
- 功能强大(400多k的包,包含很多功能)
虽然Glide 的主要目标是让任何形式的图片列表的滚动尽可能地变得更快、更平滑,但实际上,Glide几乎能满足你对远程图片的拉取/缩放/显示的一切需求。
GitHub : Glide
GitHub : 中文文档说明
另有一些基于Glide的优秀库
- glide-transformations : 一个基于Glide的transformation库,拥有裁剪,着色,模糊,滤镜等多种转换效果
- GlidePalette : 一个可以在Glide加载时很方便使用Palette的库
三、Glide应用
这里介绍了一些Glide常用用法,有如何加载图片,Glide的缓冲设置,Glide设置圆角,Glide设置图片的background,Glide加载GIF图片等,通常项目中也就用到这些内容。
3.1 依赖导入
在AS的build.gradle文件中添加
dependencies {
implementation 'com.github.bumptech.glide:glide:4.8.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.8.0'
}
3.2 布局
Glide不需要特定的布局文件,直接使用ImageView。
3.3 应用
简单应用
Glide.with(fragment)
.load(url)
.into(imageView);
// For a simple view:
@Override public void onCreate(Bundle savedInstanceState) {
...
ImageView imageView = (ImageView) findViewById(R.id.my_image_view);
GlideApp.with(this)
.load("http://xmamiga/gEgYUd.jpg")
.into(imageView);
}
// For a simple image list:
@Override
public View getView(int position, View recycled, ViewGroup container) {
final ImageView myImageView;
if (recycled == null) {
myImageView = (ImageView) inflater.inflate(R.layout.my_image_view, container, false);
} else {
myImageView = (ImageView) recycled;
}
String url = myUrls.get(position);
GlideApp
.with(myFragment)
.load(url)
.centerCrop()
.placeholder(R.drawable.loading_spinner)
.into(myImageView);
return myImageView;
}
其他配置
.with() //图片加载的环境:1,Context对象。2,Activity对象。3,FragmentActivity对象。4,Fragment对象
.load() //加载资源:1,drawable资源。2,本地File文件。3,uri。4,网络图片url。5,byte数组(可以直接加载GIF图片)
.placeholder() //图片占位符
.error() //图片加载失败时显示
.crossFade() //显示图片时执行淡入淡出的动画默认300ms
.dontAnimate() //不执行显示图片时的动画
.override() //设置图片的大小
.centerCrop() //和 fitCenter() 图片的显示方式
.animate() //view动画 2个重构方法
.transform() bitmap转换
.bitmapTransform() //bitmap转换。比如旋转,放大缩小,高斯模糊等(当用了转换后你就不能使用.centerCrop()或.fitCenter()了。)
.priority(Priority.HIGH) //当前线程的优先级
.signature(new StringSignature(“ssss”))
.thumbnail(0.1f) //缩略图,3个重构方法:优先显示原始图片的百分比(10%)
.listener() //异常监听
.into() //图片加载完成后进行的处理:1,ImageView对象。2,宽高值。3,Target对象
更多配置实例:
Glide.with(AppContext.context())
.load(url)
.placeholder(R.mipmap.placeholdermid) //占位符
.error(R.mipmap.placeholdermid) //错误占位符
.dontAnimate()//没有任何淡入淡出效果
.override(640, 428)//调整图片大小
.diskCacheStrategy(DiskCacheStrategy.ALL)
.priority(Priority.HIGH)//优先级
.into(iv);
3.4 各路径图片加载方法
从文件加载图片
File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),"Test.jpg");
Glide.with(context).load(file).into(imageViewFile);
从资源id加载图片
int resourceId = R.mipmap.ic_launcher;
Glide.with(context).load(resourceId).into(imageViewResource);
设置图片显示效果(圆角、圆形、高斯模糊、蒙板、裁剪等等)
Glide.with(this).load(R.mipmap.ic_image_sample) //模糊
.bitmapTransform(new BlurTransformation(this)) //圆角
.bitmapTransform(new RoundedCornersTransformation(this, 24, 0, RoundedCornersTransformation.CornerType.ALL)) //遮盖
.bitmapTransform(new MaskTransformation(this, R.mipmap.ic_launcher)) //灰度
.bitmapTransform(new GrayscaleTransformation(this)) //圆形
.bitmapTransform(new CropCircleTransformation(this))
.into(mResultIv);
3.5 加载资源
Glide支持网络资源、assets资源、Resources资源、File资源、Uri资源、字节数组
Glide.with(this).load("http://pic9/258/a2.jpg").into(iv);
Glide.with(this).load("file:///xxx.jpg").into(iv);
Glide.with(this).load(R.mipmap.ic_launcher).into(iv);
Glide.with(this).load(file).into(iv);
Glide.with(this).load(uri).into(iv);
Glide.with(this).load(byte[]).into(iv);
3.6 加载gif图片
加载静态gif图片(静态就是gif相当于一张图片)
Glide.with(this).load(imageUrl).asBitmap().into(iv);
加载动态gif图片(gif是动的)
Glide.with(this).load(imageUrl).asGif().into(iv);
显示本地视频
Glide 还能显示视频!只要他们是存储在手机上的。假设你通过让用户选择一个视频后得到了一个文件路径:
String filePath = "/storage/emulated/0/Pictures/example_video.mp4";
Glide.with(context).load(Uri.fromFile(new File( filePath))).into(iv);
这里需要注意的是,这仅仅对本地视频起作用。如果没有存储在该设备上的视频(如一个网络 URL 的视频),它是不工作的!
3.7 设置加载动画
默认是淡入淡出动画
Glide.with(this)
.load("http://xmamiga.com/photo/1f/1f7a.jpg")
.crossFade(int duration)//去减慢(或加快)动画
.into(iv);
使用 crossFade()
Glide.with(this)
.load("http://xmamiga.com/photo/1f/1f7a.jpg")
.crossFade()//动画默认的持续时间是 300毫秒
.into(iv);
添加自定义动画
Glide.with(this)
.load("http://xmamiga.com/photo/1f/1f7a.jpg")
.animate(R.anim.fade_in)
.into(iv);
去除动画
Glide.with(this)
.load("http://xmamiga.com/photo/1f/1f7a.jpg")
.dontAnimate()
.into(iv);
3.8 在 ListView 和 RecyclerView 中的使用
在 ListView 或 RecyclerView 中加载图片的代码和在单独的 View 中加载完全一样。Glide 已经自动处理了 View 的复用和请求的取消:
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
String url = urls.get(position);
Glide.with(fragment)
.load(url)
.into(holder.imageView);
}
对 url 进行 null 检验并不是必须的,如果 url 为 null,Glide 会清空 View 的内容,或者显示 placeholder Drawable 或 fallback Drawable 的内容。
Glide 唯一的要求是,对于任何可复用的 View 或 Target ,如果它们在之前的位置上,用 Glide 进行过加载操作,那么在新的位置上要去执行一个新的加载操作,或调用 clear() API 停止 Glide 的工作。
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
if (isImagePosition(position)) {
String url = urls.get(position);
Glide.with(fragment)
.load(url)
.into(holder.imageView);
} else {
Glide.with(fragment).clear(holder.imageView);
holder.imageView.setImageDrawable(specialDrawable);
}
}
对 View 调用 clear() 或 into(View),表明在此之前的加载操作会被取消,并且在方法调用完成后,Glide 不会改变 view 的内容。如果你忘记调用 clear(),而又没有开启新的加载操作,那么就会出现这种情况,你已经为一个 view 设置好了一个 Drawable,但该 view 在之前的位置上使用 Glide 进行过加载图片的操作,Glide 加载完毕后可能会将这个 view 改回成原来的内容。
这里的代码以 RecyclerView 的使用为例,但规则同样适用于 ListView。
3.9 Glide的缓存
用过手机的都知道,当划上划下一个ListView的时候,第二次都比第一次快,就是因为为GlideView对资源进行了缓存,而且封装的很好,甚至不需要自己去设定缓存大小,Glide会智能地自己给我们根据设备设置缓存大小。
缓存是为了减少或者杜绝多的网络请求。为了避免缓存,Glide用了内存缓存和‘外存缓存机制’,并且 提供了相应的方法,完全封装,不需要处理细节。Glide会自动缓存到内存,除非调用.skipMemoryCache( true )。尽管调用了这个,Glide还是会缓存到外存,还有一种情形,就是有一张图片,但是这张图变化非常快,这个时候可能并不想缓存到外存中,就使用.diskCacheStrategy( DiskCacheStrategy.NONE )。如果两种都不需要,可以两个方法组合着一起使用。
自定义外存缓存机制
Glide默认会缓存Image的很多个版本,比如原图,如果你的imageView大小的缓存。.diskCacheStrategy()有以下几种缓存策略:
- DiskCacheStrategy.NONE 什么都不缓存
- DiskCacheStrategy.SOURCE 只缓存最高解析图的image
- DiskCacheStrategy.RESULT 缓存最后一次那个image,比如有可能你对image做了转化
- DiskCacheStrategy.ALL image的所有版本都会缓存
四、总结
在众多的图片加载框架中,Glide是Google推荐的,并在自家的项目中大量使用的一个非常强大的框架,专注于平滑滚动,并且还提供Gif,本地Vedio首帧的解码和显示。Glide提供了非常便捷的链式调用接口,以及丰富的拓展和自定义功能,开发者可以非常简单地对框架进行配置和图片再加工。
回过头来,没有最好的框架,只有最适合自己的框架。
五、扩展
程序员开放的思想永存,网络上有先行车提供基于Glide封装的优秀库:
- glide-transformations:一个基于Glide的transformation库,拥有裁剪,着色,模糊,滤镜等多种转换效果
- GlidePalette:一个可以在Glide加载时很方便使用Palette的库