海哥 发表于 2024-11-13 00:36:22

glide性能优化实战

glide性能优化实战

前言

项目利用glide加载图片之前也只是会基本api,这次项目有非常多的图片需要展示,而且设备是一个android12的版本,但是性能不太理想,分给APP的资源不太多,以是需要优化现有图片加载逻辑,读者可以根据自己的项目自行选择优化项。
关于Glide的简单先容

Glide是一个快速高效的Android图片加载库,注重于平滑的滚动。Glide提供了易用的API,高性能、可扩展的图片解码管道(decode pipeline),以及主动的资源池技术。
Glide 支持拉取,解码和展示视频快照,图片,和GIF动画。Glide的Api是云云的机动,开发者甚至可以插入和替换成自己喜爱的任何网络栈。默认情况下,Glide利用的是一个定制化的基于HttpUrlConnection的栈,但同时也提供了与Google Volley和Square OkHttp快速集成的工具库。
虽然Glide 的主要目的是让任何情势的图片列表的滚动尽可能地变得更快、更平滑,但实际上,Glide险些能满意你对远程图片的拉取/缩放/体现的一切需求。
API

Glide 利用简明的流式语法API,这是一个非常棒的计划,因为它允许你在大部门情况下一行代码搞定需求:
Glide.with(context)
    .load(url)
    .into(imageView);
性能

Glide 充分考虑了Android图片加载性能的两个关键方面:


[*]图片解码速度
[*]解码图片带来的资源压力
为了让用户拥有良好的App利用体验,图片不仅要快速加载,而且还不能因为过多的主线程I/O或频繁的垃圾回收导致页面的闪耀和抖动征象。
Glide利用了多个步调来确保在Android上加载图片尽可能的快速宁静滑:


[*]主动、智能地下采样(downsampling)和缓存(caching),以最小化存储开销和解码次数;
[*]积极的资源重用,例如字节数组和Bitmap,以最小化昂贵的垃圾回收和堆碎片影响;
[*]深度的生命周期集成,以确保仅优先处理活泼的Fragment和Activity的请求,并有利于应用在须要时开释资源以避免在后台时被杀掉。
关于Glide的初步优化

上面都是官网的先容,下面我们进行初步的一个优化。
缓存计谋

起首是图片的缓存计谋。几个可配置的缓存计谋属性在DiskCacheStrategy类中都有先容


[*] NONE 不利用缓存,每次都重新加载
[*] DATA 在解码之前,将检索到的数据直接写入磁盘缓存。
[*] RESOURCE 在解码后,再将检索到的数据写入磁盘缓存。
[*] AUTOMATIC 实验根据DataFetcher和EncodeStrategy中的ResourceEncoder(假如ResourceEncoder可用的话)的数据源智能地选择计谋。
[*] ALL 假如是远程数据利用DATA和RESOURCE缓存,假如是当地数据利用RESOURCE缓冲。
项目加载的都是当地图片,以是在加载速度和缓存巨细的权衡下,利用了RESOURCE
...
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
...
图片裁剪

因为缓存巨细跟图片巨细是有直接关系的,以是加载前最好将其裁剪为和控件巨细一致,避免过大的图片造成ANR和Out Of Memory
...
.override(your size)
...
移除加载动画

Glide为了保证图片加载的过分流通性,不显得突兀,是有默认的动画和变换的,但这也会斲丧一定的性能,以是我们将它关闭
...
.dontAnimate()
.dontTransform()
...
其他

(可选)假如需要在加载过程中对图片进行处理,可以利用RequestListener
初步效果

都加上过后大概是这个样子
Glide.with(context)
    .load(url)
        .override(your size)
        .dontAnimate()
    .dontTransform()
        .diskCacheStrategy(DiskCacheStrategy.RESOURCE)
    .into(imageView);
可以从Profiler中看到加载一个list的图片时,内存和CPU都有降落。
关于Glide的AppGlideModule定制

在新版Glide中,可以通过自界说AppGlideModule来全局界说glide的设置
import android.content.Context
import com.bumptech.glide.Glide
import com.bumptech.glide.GlideBuilder
import com.bumptech.glide.Registry
import com.bumptech.glide.annotation.GlideModule
import com.bumptech.glide.load.DecodeFormat
import com.bumptech.glide.load.engine.bitmap_recycle.LruArrayPool
import com.bumptech.glide.load.engine.bitmap_recycle.LruBitmapPool
import com.bumptech.glide.load.engine.cache.DiskLruCacheWrapper
import com.bumptech.glide.load.engine.cache.LruResourceCache
import com.bumptech.glide.load.engine.cache.MemorySizeCalculator
import com.bumptech.glide.load.engine.executor.GlideExecutor
import com.bumptech.glide.module.AppGlideModule
import com.bumptech.glide.request.RequestOptions
import com.fawvw.hmi.media.common.utils.LogUtil
import java.io.File

@GlideModule
class MyAppGlideModule : AppGlideModule() {

    private val TAG = "MyAppGlideModule"
    //图片文件缓存 10M
    private var IMAGE_CACHE_COUNT = 10 * 1024 * 1024
    private val SOURCE_EXECUTOR_NAME = "source"
    private val ANIMATION_EXECUTOR_NAME = "animation"

    override fun applyOptions(context: Context, builder: GlideBuilder) {
      super.applyOptions(context, builder)

      val calculator = MemorySizeCalculator.Builder(context).build()
      val defaultMemoryCacheSize = calculator.memoryCacheSize
      val defaultBitmapPoolSize = calculator.bitmapPoolSize
      val defaultArrayPoolSize = calculator.arrayPoolSizeInBytes
      LogUtil.d(
            TAG,
            "defaultMemoryCacheSize: $defaultMemoryCacheSize, defaultBitmapPoolSize: $defaultBitmapPoolSize, defaultArrayPoolSize: $defaultArrayPoolSize"
      )
      builder.setDefaultRequestOptions(
            RequestOptions().format(DecodeFormat.PREFER_RGB_565)
      )

      val cacheLocation = File(context.externalCacheDir, "GlideCache")
      if (!cacheLocation.exists()) {
            cacheLocation.mkdirs()
      }
      //设置glide文件缓存为10M
      builder.setDiskCache {
            DiskLruCacheWrapper.create(cacheLocation, IMAGE_CACHE_COUNT.toLong())
      }
      //设置glide内存,bitmap池,数组池砍
      builder.setMemoryCache(LruResourceCache((defaultMemoryCacheSize / 4).toLong()))
      builder.setBitmapPool(LruBitmapPool((defaultBitmapPoolSize / 4).toLong()))
      builder.setArrayPool(LruArrayPool(defaultArrayPoolSize / 4))

      //设置Source线程最大数量为1
      builder.setSourceExecutor(
            GlideExecutor.newSourceBuilder()
                .setThreadCount(1)
                .setName(SOURCE_EXECUTOR_NAME)
                .build()
      )
      //设置Animation线程最大数量为1
      builder.setAnimationExecutor(
            GlideExecutor.newAnimationBuilder()
                .setThreadCount(1)
                .setName(ANIMATION_EXECUTOR_NAME)
                .build()
      )
    }

    override fun registerComponents(context: Context, glide: Glide, registry: Registry) {
      super.registerComponents(context, glide, registry)
    }
}
编译过后,就可以调用GlideApp了,用于将Glide替换掉,注意别忘了添加@GlideModule注解。
总结

在进行了上面的两个定制过后,CPU和内存都有显着的降落,但是有些配置确实会导致加载速度变慢和用户体验变差,需要自己权衡。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: glide性能优化实战