本文正在参与「金石计划」

对于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的文档是怎么说的(文档地址中文地址 最新英文地址):

7个你应该知道的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释放图片资源

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

如上图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
                }
            })

优先加载指定图片

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

如上图所示,当一个页面有多个图片时,咱们期望某些图片优先被加载出来(这个界面里边是上面的一拳超人的封面),某些图片后加载,比方这个界面里的互动点评的用户头像列表。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.with(View)

咱们知道,Glide依据with()里边的参数来决定load的生命周期。

  • 当运用with(getActivity().getApplicationContext())时,即便当前activity或许Fragment被destory,它将继续load图片,然后图片被解码、缓存,乃至或许被设置到ImageView中,最后才被废物收回;
  • 当运用with(Fragment)时,Glide会监听Fragment的生命周期,一旦Fragment被中止,任何未完结的恳求都会被暂停;而当销毁时,所有未完结的恳求都会被清除。
  • 运用with(getActivity())时,Glide会监听Activity的生命周期,只有在Activity被中止或销毁的时分,才会暂停或许清除未完结的load恳求。
  • 运用with(view)时,Glide将做与with(view.getContext())相同的事情,这相当于上面的Activity状况,而不是with(Fragment)。

加载大图时运用skipMemoryCache

当咱们运用Glide加载大图时,应该防止运用内存缓存,如果不好好处理或许发生oom。在Glide中,咱们能够运用skipMemoryCache来跳过内存缓存。代码如下:

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

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

参阅

  • Glide transform 问题剖析
  • Glide官方文档