Glide基础入门
原文地址
转载于公众号(一个很不错的公众号):
一、前言
Glide 现在大范围的使用在各种商业项目中,而对于一般而言, Glide 的 Api 封装的非常好,多数情况下我们只需要使用它,在使用的基础之上,才考虑如何了解它。
本文的目的是让你如何快速上手 Glide 3.x ,来快速投入开发,本文力求做到快速上手,所以只讲在上手的时候,你需要关注的。
二、简单使用
2.1 什么是 Glide ?
既然要用到 Glide ,那就先简单的介绍一下 Glide 。
Glide 简单来说就是一个 Google 主导的图片加载开源库。它稳定、速度快、可自适应图片尺寸、支持众多格式、支持加载不同来源的图片、内存和磁盘缓存的优化。这些,都是它的好处(当然不止这些),这里就不一一细说了。
你只需要知道,它是一款主流的图片加载库即可,它包含了你能想到的所有功能,并且支持扩展。
Glide 的 Github 地址
2.2 在项目内集成 Glide
虽然它已经到 v4.x 了,但是本文还是就最常用的 v3.8.0 版本的集成,做一个简单的介绍。
集成的方式有多种,可以直接引用 jar 包,也可以使用 Maven,这里还是使用主流的 Gradle 来集成它。
1 | dependencies { |
如果需要配置混淆,还需要在混淆文件中区分 Glide 。
1 | -keep public class * implements com.bumptech.glide.module.GlideModule |
配好 Glide ,我们就可以开始使用它了。
2.3 最简单的使用
Glide 是支持链式调用的,但是它不是简单的在每个方法中返回 this ,它更复杂一些,后面会讲到,所以通常使用它只需要使用一条语句即可。
1 | ImageView imageView = (ImageView) findViewById(R.id.my_image_view); |
这是一个最简单的 Glide 的 Demo,使用它即可从网络上加载一张图片到一个 ImageView 中去显示。
三、Glide 需要了解的内容
前面的例子可以看到,实际上 Glide 的链式调用,它的主要方法就是三个,先来简单看看他们:
- with:主要是传递一个 Glide 可用的 Context,它和生命周期相关。
- load:接收一个待加载的图片资源,可支持多种格式。
- into:指定加载的图片的最终使用目标对象,例如可以是一个 ImageView。
这三个主要的部分,贯穿了 Glide 使用的主要重点内容,接下来让我们好好看看他们。
3.1 with()
前面提到,这里的 with() 方法用于给 Glide 传递一个 Context 对象,它可以支持多种 Context:
对于 with 而言,它会返回一个 RequestManager 用于管理请求,而它接收的这些不同的 Context ,并不是为了让我们方便使用,而是会对当前 Context 的生命周期做监听,来管理 Glide 自身的图片加载的请求。
举个例子:当使用 with(Activity) 的时候,如果此时当前 Activity 被关闭掉了,那么 Glide 就会将这个 Activity 下所有的图片请求停止掉。也就是实现了 Glide 和 页面生命周期的绑定,来优化 Glide 自身的请求策略。
所以,在使用 Glide 的时候,尽量使用当前页面的 Activity ,而非直接传递一个 Context 进去。尽量小的选择 Context 的范围,他们的推荐优先级为:Fragment
->Activity
->Context
3.2 load()
load() 方法,就是去指定一个待加载的资源,它支持很多格式和资源种类。例如:网络地址、本地文件、Drawable 等,它都是可以做到很好的加载的。
load() 方法,并不是在 Glide 中,前面也提到 with() 会返回一个 RequestManager 对象,load() 方法在它内部实现:
具体 load() 方法,支持的资源种类,可以看到它方法的重载,基本上我们能想到的,它都支持,它返回的是另外一个 DrawableTypeRequest 对象。
3.3 into()
into() 方法,用于指定加载的图片资源,最终给谁来使用。加载的图片,最终一定是用来显示的,所以它需要指定一个使用图片的对象。into() 实际上是 DrawableTypeRequest 中的方法,DrawableTypeRequest 是一个多层继承的类,它实际上自己是没有对 into() 方法的实现的,大部分实现都是在其父类 DrawableRequestBuilder 和 父类的父类 GenericRequestBuilder 中的:
从上可以看到 into() 不只是可以接受一个 ImageView ,也可以是一些其他的什么。这也很好理解,在项目内,也不仅仅只有 ImageView 可以用来显示图片,View 的 background 也是可以用于显示图片的。
四、Glide 的使用细节
既然 Glide 使用过程中,最重要的三个方法已经介绍过了,他们是 Glide 能完成功能的基础,接下来,就开始介绍 Glide 的使用细节,来见证 Glide 的强大。
本节介绍的 Glide 的使用细节,基本上都是与 load() 方法返回的 DrawableTypeRequest 对象进行操作,对其进行一些配置。
4.1 不同状态的占位图
在图片加载的过程中,会经历过多过程,例如:加载中、加载失败等等,在这些过程中,其实是可以为暂时为 ImageView 设置一个占位的的,来定制加载中、加载失败这种状态的显示效果。
Glide 定制的占位图,有三种:
- placeholder :指定加载前显示的图片资源。
- error:指定加载失败显示的图片资源。
- fallback:指定传递加载资源为 null 的时候,显示的图片资源。
例如上面的例子中,其实 fallback() 是无需指定的,因为 imageUri 是不可能为 null 的。而其他的,都会在不同的阶段显示出来,加载前会显示 load_placeholder ,如果加载失败了,会显示 load_error 。不同状态的占位图,实际上是一种容错的表现,所以只能用于加载一个本地资源
,允许传递一个 @DrawableId 或者 Drawable 对象。
4.2 缩放控制
某些时候,因为图片的尺寸和控件的尺寸,不一定能匹配,所以会对图片的显示效果,进行一些缩放,而大多数情况下,这种默认的缩放策略,并不是我们想要的,Glide 提供了一些方法来控制缩放的效果:
- centerCrop()
- fitCenter()
这两个方法和 ImageView.setScaleType() 中传递的参数效果类似,就不再一一赘述了。
4.3 缓存控制
现在基本上所有的图片加载库,都是遵照三级缓存的策略:网络、磁盘、内存,Glide 也是如此,为了更好的体验,这些缓存默认都是全部开启的。
1、内存缓存,有或没有,Glide 提供了一个 skipMemoryCache() 方法传递一个 Boolean 的值用于指定是否跳过磁盘缓存,默认是 false ,表示需要内存缓存。
2、磁盘缓存,为了保证效率,默认会去缓存多种尺寸的图片在磁盘上的,也就是说,对于同一个 Uri,如果在不同尺寸的 ImageView 中使用到它了,默认在设备的磁盘上也会有多张不同尺寸的图片。这样下次加载的时候速度更快,是一种以空间换效率的策略。
3、磁盘缓存,需要使用 diskCacheStrategy() 方法来改变它,它是一种比较复杂的策略,它需要传递一个 DiskCacheStrategy 的枚举类型:
1 | /** |
上面的例子就是忽略内存缓存,并且磁盘只缓存原图的策略。
4.4 加载优先级
对于同一个页面,如果需要在多个地方都加载线上图片,必然会存在一个优先级的问题。例如:正常来说,背景图是比其他图片优先级更高的图片。
Glide 是可以在加载中,对当前加载的图片,调整加载的优先级的。需要使用 priority() 方法,它可以接受一个 Priority 的枚举类型,包含四种值:LOW(低)、HIGH(高)、NORMAL(普通)、IMMEDIATE(立即)。
可以在我们需要的时候,对其进行配置,他只是用于 Glide 在加载图片的时候一个优化请求的参数而已,并不影响最终显示的顺序。
1 | ImageView imageView = (ImageView) findViewById(R.id.my_image_view); |
4.5 载入动画
Glide 在显示图片的时候,为了让显示效果不那么突兀,会以一种更柔和的方式去显示,就会在加载的时候给一个动画效果,它可以使用 crossFade() 方法进行配置,如果不特殊处理,默认它是开启的,默认动画的时长是 300ms。
crossFade() 也是有多个重载的,主要是为了指定动画以及动画的时长。而 crossFade() 的源码中实际上只是对 animate() 方法的一个包装而已。crossFade() 的效果是默认开启的,所以如果不需要这个动画效果,可以使用 dontAnimate() 来禁用动画效果。
有一些情况下,crossFade() 方法并不能满足我们的需求。如果对加载的动画有特殊的定制需要,可以使用更灵活的 animate() 方法来自己实现动画。
可以看到,animate() 支持多种格式的动画的配置,对于动画的效果,这里就不一一讲解了。
1 | ViewPropertyAnimation.Animator animator = new ViewPropertyAnimation.Animator(){ |
4.6 支持 Gif & 视频
Glide 的一个非常棒的功能,就是可以支持 Gif,并且使用起来和正常的想要加载一张网络上的图片,并没有什么区别。但是有时候我们需要对加载的 Gif 图做一个检查,例如校验它是否是一个 Gif ,如果不是,则认为是一次错误的加载。这个时候就可以使用 asGif() 来进行校验,如果当前加载的图片不是一个正确的 Gif 格式,则会去显示 error() 配置的图片。
1 | ImageView imageView = (ImageView) findViewById(R.id.my_image_view); |
当然,有时候我们可能只是为了显示一张图片,可以强制显示 Gif 图片的第一帧,使用 asBitmap() 方法标记即可(将 asGif() 替换成 asBitmap() 就可以了)。
Glide 对 Gif 的支持之外,提示还对 Video 格式的文件也进行了支持。但是它和 Gif 显示的效果不一样的一点在于,它并不会去播放视频文件,而只是将视频文件的第一帧做为一个图片去显示出来。如果依然想要播放一段视频文件,使用 Glide 不是一个好注意,你应该使用 VideoView。
其次 Glide 对视频的支持,仅限于本地视频,并无法对网络视频进行支持。
1 | ImageView imageView = (ImageView) findViewById(R.id.my_image_view); |
4.7 加载监听
如果有对 Glide 加载的图片的结果进行监听的,可以使用 listener() 方法设置一个监听器,它接收一个 RequestListener 的接口
1 | RequestListener listener = new RequestListener<String, GlideDrawable>() { |
一般而言,如果我们需要监听图片加载错误的原因,可以在 onException() 中做处理。
需要注意的是,这两个方法的返回值,最好都是 false,因为如果返回 true ,将表示你已经处理了这次的事件,而 Glide 将不会再做额外的处理。例如,如果 onException() 返回了 true 的话,在图片加载失败之后,error() 中设置的图片,并不会被显示,因为 Glide 认为开发者已经在外部对这个错误进行了处理。
4.8 变换加载的图片
对于使用 Glide 加载的图片,如果想要在其显示之前,对其进行一些变换操作,例如,改变颜色、虚化、圆角子类的,都需要用到 transfrom() 方法,它主要用于支持在图片显示之前,自定义的变换效果。
变换有两个方法:
- transfrom():它可以添加一个通用的变换效果。
- bitmapTransfrom():限制了变换的类型,只能设置 Bitmap 的变换。
变换这种操作,其实定制性非常的强,展开讲就比较复杂了,只需要知道,Glide 是可以对加载的图片在显示之前进行一些预处理的操作的,在具体使用的时候再回头来看相关资料即可。
这里推荐一个开源的库,来支持大多数变换的效果。
4.9 into() 其他实现
前面所有的例子中,into() 方法作为 Glide 加载图片流程的最后一个环节,它不仅仅只能支持一个 ImageView。有时候我们还需要给 View 中设置一个背景的需要,这个使用 Glide 也是可以办到的,但是就需要用到 into() 方法的其他重载方法了。
撇开 into(ImageView) 不说,into(int,int) 实际上是一个指定尺寸的同步方法,可以在子线程中,通过它来得到一个 GlideDrawable 对象。
1 | new Thread(new Runnable() { |
但是这并不是很常用的场景,大部分我们还是使用泛型的方式来使用 Glide 的。
1 | /** |
它的完整签名可以看出,它实际上接收的是一个 Target 对象,而 Glide 同时也提供了非常多的 Target 的子类。
这些子类里面,有一些是不常用的,例如 AppWidgetTarget 和 NotificationTarget 就是为了 AppWidget 和 Notification 中加载图片准备的。这里只介绍两个比较常用的 Target :SimpleTarget 和 ViewTarget ,其实使用起来都是大同小异。
如果我们不关心图片加载的用途,只是单纯的需要加载一个 Bitmap 或者 Drawable ,就可以使用 SimpleTarget 来处理。
1 | final ImageView imageView = (ImageView) findViewById(R.id.my_image_view); |
SimpleTarget 可以接受一个 GlideDrawable 或者 Bitmap 的类型作为加载的类型。如果需要指定加载的图片尺寸,还可以在构造方法中指定,如果不对其进行指定,则加载的是图片的原尺寸。
再来看看 ViewTarget, 从名称上可以才出来,它实际上是想让 Glide 加载一个图片资源给某个 View 使用。它可以解决有时候我们显示图片的 View 并不是一个 ImageView 的问题,也可能是一个 View 的背景。
1 | final ImageView imageView = (ImageView) findViewById(R.id.my_image_view); |
ViewTarget 需要指定 View 的类型,以及加载的资源类型,这里直接使用的 View 和 GlideDrawable ,然后将我们需要的使用图片的目标 View 当构造参数传递进去即可,最终它它会一个内部 view 变量去持有它,供之后使用,在 onResourceReady() 这个回调方法中,直接按我们的需要使用 GlideDrawable 和 View 即可。
如果是需要在非 ImageView 的其他 View 上使用图片,推荐使用 ViewTarget 。它内部是会去计算 View 的尺寸,来优化缓存的图片。和加载 ImageView 的效果是一样的,如果使用 SimpleTarget 就需要考虑到 View 的尺寸问题了。
在使用 Target 的时候,还有一点需要额外注意的,如果不是和页面绑定的图片资源,可以使用 ApplicationContext() ,避免当前页面被销毁之后,加载的请求也被停止了。
五、小结
本文最开始只是想要做一个适合初学者快速上手的 Glide 使用手册,但是越写越长,读到这里相信你也能有所收获,之后如果觉得有写概念也需要初学者了解,会继续补充。