注册

7个你应该知道的Glide的使用技巧

对于Android开发者来说,Glide是最常使用的库。这里介绍了开发过程中,7个使用Glide的技巧。

不要使用wrap_content

不清楚你是否这样使用过,把 ImageView 的宽和高设置成 wrap_content,并通过Glide来加载图片

<ImageView
android:id="@+id/image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>

Glide.with(context)
.load(url)
.into(image)

为什么不建议把ImageView设置成 wrap_content,我们看一下Glide的文档是怎么说的(文档地址中文地址 最新英文地址):

文档上写得很明显,在某些情况下会使用屏幕的尺寸代替 wrap_content,这可能导致原来的小图片变成大图,Glide transform 问题分析这篇文章就介绍了这种问题。为了避免这种情况发生,我们最好是不要使用 wrap_content。当然如果你实在是需要使用 wrap_content,你可以按照Glide的建议,使用Target.SIZE_ORIGINAL。

需要注意的是:使用Target.SIZE_ORIGINAL 在加载大图时可能造成oom,因此你需要确保加载的图片不会太大。

自定义内存缓存大小

在某些情况下,我们可能需要自定义Glide的内存缓存大小和Bitmap池的大小,比如图片显示占大头的app,就希望Glide的图片缓存大一些。Glide内部使用MemorySizeCalculator类来决定内存缓存和Bitmap池的大小。

@GlideModule
class MyGlideModel: AppGlideModule() {

override fun applyOptions(context: Context, builder: GlideBuilder) {
super.applyOptions(context, builder)
//通过MemorySizeCalculator获取MemoryCache和BitmapPool的size大小
val calculator = MemorySizeCalculator.Builder(context).build()
val defaultMemoryCacheSize = calculator.memoryCacheSize
val defaultBitmapPoolSize = calculator.bitmapPoolSize

//根据业务计算出需要的缓存大小,这里简化处理,都乘以1.5
val customMemoryCacheSize = (1.5 * defaultMemoryCacheSize).toLong()
val customBitmapPoolSize = (1.5 * defaultBitmapPoolSize).toLong()
//设置缓存
builder.setMemoryCache(LruResourceCache(customMemoryCacheSize))
builder.setBitmapPool(LruBitmapPool(customBitmapPoolSize))
}
}

memoryCache 和 BitmapPool 的区别:

  • memoryCache:通过key-value才缓存数据,缓存之前用过的Bitmap
  • BitmapPool:重用Bitmap对象的对象池,根据Bitmap的宽高来复用。复用的原理可以看Bitmap全解析

具体区别见What is difference between MemoryCacheSize and BitmapPoolSize in Glide

自定义磁盘缓存

Glide 使用 DiskLruCacheWrapper 作为默认的 磁盘缓存 。 DiskLruCacheWrapper 是一个使用 LRU 算法的固定大小的磁盘缓存。默认磁盘大小为 250 MB ,位置是在应用的 缓存文件夹 中的一个 特定目录 。我们也可以自定义磁盘缓存,代码如下:

@GlideModule

class MyGlideModel: AppGlideModule() {

override fun applyOptions(context: Context, builder: GlideBuilder) {
super.applyOptions(context, builder)
val size: Long = 1024 * 1024 * 100 //100MB
builder.setDiskCache(InternalCacheDiskCacheFactory(context, cacheFolderName, size))
}
}

牢记在onLoadCleared释放图片资源

如上图Glide的官方文档所示,我们在使用Target时,必须在重新绘制(通常是View)或改变其可见性之前,你必须确保在onResourceReady中收到的任何当前Drawable不再被使用。这是因为Glide内部缓存在内存不足或者主动回收Glide.get(context).clearMemory()时,会回收Bitmap,如果此时ImageView还使用被回收的Bitmap,就会发生 trying to use a recycled bitmap 的错误。

解决办法是不再使用在onResourceReady中获取的Bitmap,代码如下:

        Glide.with(this)
.load(Url)
.into(object : CustomTarget<Bitmap>(width, height) {
override fun onResourceReady(
resource: Bitmap,
transition: Transition<in Bitmap>?,
) {
mBitmap = resource
}

override fun onLoadCleared(placeholder:Drawable?){
mBitmap = null
}
})

优先加载指定图片

如上图所示,当一个页面有多个图片时,我们希望某些图片优先被加载出来(这个界面里面是上面的一拳超人的封面),某些图片后加载,比如这个界面里的互动点评的用户头像列表。Glide提供了优先级来解决这个问题,它的优先级如下:

  • Priority.LOW
  • Priority.NORMAL
  • Priority.HIGH
  • Priority.IMMEDIATE

使用代码如下:

    Glide
.with(context)
.load("url")
.priority(Priority.LOW)//底优先级的图片
.into(imageView);

Glide
.with(context)
.load("url")
.priority(Priority.HIGH)//高优先级的图片
.into(imageView);

注意:优先级高的加载任务会尽量首先启动,但是无法保证加载开始或完成的顺序。

使用Glide前,先判断页面是否回收

一般我们会通过网络请求来获取图片的链接,再通过Glide来加载图片,代码如下:

service?.fetchUserProfile(id) { result, errMsg, icon ->
if (result == 200) {
Glide.with(context)
.load(icon)
.into(view)
}
}

但是这里有个问题,当界面被destory后,这个网络请求刚好成功了,调用Glide.with就会发生 You cannot start a load for a destroyed activity错误。解决方法是在调用Glide.with前先判断,代码如下:


service?.fetchUserProfile(id) { result, errMsg, icon ->
if (result == 200) {
if (context is FragmentActivity) {
if ((context as FragmentActivity).isFinishing || (context as FragmentActivity).isDestroyed) {
return
}
}
Glide.with(context)
.load(icon)
.into(view)
}
}

加载大图时使用skipMemoryCache

当我们使用Glide加载大图时,应该避免使用内存缓存,如果不好好处理可能发生oom。在Glide中,我们可以使用skipMemoryCache来跳过内存缓存。代码如下:

    Glide.with(context)
.load(url)
.skipMemoryCache(true)
.into(imageview)

与skipMemoryCache对应的是 onlyRetrieveFromCache,它只从缓存中获取对象,不会从网络或者本地缓存中就直接加载失败。


作者:小墙程序员
链接:https://juejin.cn/post/7215977393696309307
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

0 个评论

要回复文章请先登录注册