google推荐的图片加载库Glide的一些坑
Glide简介:
Glide 是 Google 员工的开源项目, Google I/O 上被推荐使用,一个高效、开源、Android设备上的媒体管理框架,它遵循BSD、MIT以及Apache 2.0协议发布。Glide具有获取、解码和展示视频剧照、图片、动画等功能,它还有灵活的API,这些API使开发者能够将Glide应用在几乎任何网络协议栈里。创建Glide的主要目的有两个,一个是实现平滑的图片列表滚动效果,另一个是支持远程图片的获取、大小调整和展示。
Glide特点
使用简单
可配置度高,自适应程度高
支持常见图片格式:Jpg png gif webp
支持多种数据源:网络、本地、资源、Assets 等
高效缓存策略:支持Memory和Disk图片缓存 默认Bitmap格式采用RGB_565内存使用至少减少一半
生命周期集成:根据Activity/Fragment生命周期自动管理请求
高效处理Bitmap:使用Bitmap Pool使Bitmap复用,主动调用recycle回收需要回收的Bitmap,减小系统回收压力
Glide作为google推荐的图片加载库,现在我们来了解一些它的使用及其一些坑
1.Glide简单使用
1.)添加引用 build.gradle 中添加配置
|
|
2.)设置绑定生命周期
我们可以更加高效的使用Glide提供的方式进行绑定,这样可以更好的让加载图片的请求的生命周期动态管理起来
|
|
3.)简单的加载图片实例
|
|
4.)设置加载中以及加载失败图片
api里面对placeholder()、error()函数中有多态实现 用的时候可以具体的熟悉一下
|
|
5.)设置跳过内存缓存
|
|
6.)设置下载优先级
|
|
7.)设置缓存策略
|
|
策略解说:
all:缓存源资源和转换后的资源
none:不作任何磁盘缓存
source:缓存源资源
result:缓存转换后的资源
8.)设置加载动画
api也提供了几个常用的动画:比如crossFade()
|
|
R.anim.item_alpha_in
|
|
9.)设置缩略图支持
这样会先加载缩略图 然后在加载全图
|
|
10.)设置加载尺寸
|
|
11.)设置动态转换
|
|
api提供了比如:centerCrop()、fitCenter()等函数也可以通过自定义Transformation,举例说明:比如一个人圆角转化器
|
|
具体使用
|
|
12.)设置要加载的内容
项目中有很多需要先下载图片然后再做一些合成的功能,比如项目中出现的图文混排,该如何实现目标下
|
|
13 .)设置监听请求接口
|
|
设置监听的用处 可以用于监控请求发生错误来源,以及图片来源 是内存还是磁盘
14.)设置动态GIF加载方式
|
|
15.)缓存的动态清理
|
|
2.Glide的坑
1.)ImageView的setTag问题
问题描述:如果使用Glide的into(imageView)为ImageView设置图片的同时使用ImageView的setTag(final Object tag)方法,将会导致java.lang.IllegalArgumentException: You must not call setTag() on a view Glide is targeting异常。因为Glide的ViewTarget中通过view.setTag(tag)和view.getTag()标记请求的,由于Android 4.0之前Tag存储在静态map里,如果Glide使用setTag(int key, final Object tag)方法标记请求则可能会导致内存泄露,所以Glide默认使用view.setTag(tag)标记请求,你就不能重复调用了。
解决办法:如果你需要为ImageView设置Tag,必须使用setTag(int key, final Object tag)及getTag(int key)方法,其中key必须是合法的资源ID以确保key的唯一性,典型做法就是在资源文件中声明type=”id”的item资源。
2.)placeholder()导致的图片变形问题
问题描述:使用.placeholder()方法在某些情况下会导致图片显示的时候出现图片变形的情况。这是因为Glide默认开启的crossFade动画导致的TransitionDrawable绘制异常,详细描述和讨论可以看一下这个#363 issue。根本原因就是你的placeholder图片和你要加载显示的图片宽高比不一样,而Android的TransitionDrawable无法很好地处理不同宽高比的过渡问题,这的确是个Bug,是Android的也是Glide的。
解决办法:使用.dontAnimate()方法禁用过渡动画,或者使用animate()方法自己写动画,再或者自己修复TransitionDrawable的问题。
3.)异步线程完成后加载图片的崩溃问题
问题描述:通常情况下,异步线程会被约束在Activity生命周期内,所以异步线程完成后使用Glide加载图片是没有问题的。但如果你的异步线程在Activity销毁时没有取消掉,那么异步线程完成后就Glide就无法为一个已销毁的Activity加载图片资源,抛出的异常如下(在with()方法中就进行判断并抛出异常):
You cannot start a load for a destroyed activity ,这个异常,是因为相关 Activity/Fragment 已经 destroy,而程序代码中依然在使用 Glide 加载图片导致的。抛出异常的方法是在 RequestManagerRetriever.Java 类里面:
|
|
解决办法:
出现这个的原因是没有了解 Glide 是与 Activity/Fragment 的生命周期相关联的,这也是为什么 with(this) 有那么多的重载方法。
官方推荐使用下面的方式:
|
|
|
|
使用的时候:
|
|
RequestManager 是帮助管理生命周期的,使得 Glide 的生命周期与 Activity/Fragment 保持同步,如果 Activity/Fragment 销毁,相关 Glide 加载也会进行销毁,从而达到不浪费内存的目的,这也是不推荐使用 getApplicationContext() 作为参数的原因。
4.)ImageView的资源回收问题
问题描述:默认情况下,Glide会根据with()使用的Activity或Fragment的生命周期自动调整资源请求以及资源回收。但是如果有很占内存的Fragment或Activity不销毁而仅仅是隐藏视图,那么这些图片资源就没办法及时回收,即使是GC的时候。
解决办法:可以考虑使用WeakReference,如:
|
|
5.)ImageView的scaleType问题
scaleType默认为fitCenter模式,如果你想设置成centerInside,不好意思,3.x还没有这个方法,参见这个#591 issue,折中的解决办法就是放弃使用centerInside,或者结合android:scaleType=”centerInside”和.dontTransform()使用以禁止Glide对资源进行转换。
如果你想要ImageView的宽高根据图片资源的大小而定(即使用wrap_comtent),那么你就必须明确告诉Glide我想加载原始资源:使用android:scaleType=”center”,或者.dontTransform(),或者.override(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL)。
不推荐使用fitXY,因为这样Glide会加载全尺寸图像到内存中而造成不必要的内存占用。
3.一些使用技巧
1.)Glide.with(context).resumeRequests()和 Glide.with(context).pauseRequests()
当列表在滑动的时候,调用pauseRequests()取消请求,滑动停止时,调用resumeRequests()恢复请求。这样是不是会好些呢?
2.)Glide.clear()
当你想清除掉所有的图片加载请求时,这个方法可以帮助到你。
3.)ListPreloader
如果你想让列表预加载的话,不妨试一下ListPreloader这个类。
4.一些基于Glide的优秀库
1.)glide-transformations
glide-transformations
一个基于Glide的transformation库,拥有裁剪,着色,模糊,滤镜等多种转换效果,赞的不行不行的~~
2.)GlidePalette
GlidePalette
一个可以在Glide加载时很方便使用Palette的库。