You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Coil中将大图转为缩略图?Gallery应用LazyColumn性能优化求助

针对Gallery应用LazyColumn缩略图加载性能的优化策略

先修复现有Decoder的致命逻辑错误

你的自定义Decoder里存在缓存命中后仍重复生成缩略图的问题:当tempBitmap != null时,你创建了DecodeResult但没有return,导致后续代码依然会执行ThumbnailUtils.createImageThumbnail,完全浪费了缓存的意义,这是性能差的核心原因之一。修复后代码如下:

class ImageDecoder constructor(
    private val sourceResult: SourceResult,
    private val options: Options
) : Decoder {

    @SuppressLint("NewApi")
    override suspend fun decode(): DecodeResult = withContext(Dispatchers.IO) {
        try {
            val file = sourceResult.source.file().toFile()
            val tempBitmap = bitmapCache.get(file.path)

            if (tempBitmap != null) {
                // 缓存命中直接返回,终止后续执行
                return@withContext DecodeResult(
                    drawable = BitmapDrawable(options.context.resources, tempBitmap),
                    isSampled = false
                )
            }
            
            val localBitmap = ThumbnailUtils.createImageThumbnail(file, android.util.Size(200, 200), null)
            bitmapCache.put(file.path, localBitmap)
            
            DecodeResult(
                drawable = BitmapDrawable(options.context.resources, localBitmap),
                isSampled = false
            )
        } catch (e: Exception) {
            DecodeResult(
                drawable = options.context.getDrawable(R.drawable.image_icon)!!,
                isSampled = false
            )
        }
    }
}

替换低效的缩略图生成方式

ThumbnailUtils.createImageThumbnail的性能并不理想,建议改用BitmapFactory结合采样率控制,直接从文件流解码出指定尺寸的缩略图,减少内存占用和解码时间:

private fun decodeThumbnail(file: File, targetSize: Int): Bitmap? {
    val options = BitmapFactory.Options().apply {
        inJustDecodeBounds = true
        BitmapFactory.decodeFile(file.path, this)
        // 计算合适的采样率,确保解码后的图片不超过目标尺寸
        inSampleSize = calculateInSampleSize(this, targetSize, targetSize)
        inJustDecodeBounds = false
        inPreferredConfig = Bitmap.Config.RGB_565 // 降低内存占用,缩略图足够用
    }
    return BitmapFactory.decodeFile(file.path, options)
}

private fun calculateInSampleSize(options: BitmapFactory.Options, reqWidth: Int, reqHeight: Int): Int {
    val (height: Int, width: Int) = options.run { outHeight to outWidth }
    var inSampleSize = 1

    if (height > reqHeight || width > reqWidth) {
        val halfHeight: Int = height / 2
        val halfWidth: Int = width / 2

        while (halfHeight / inSampleSize >= reqHeight && halfWidth / inSampleSize >= reqWidth) {
            inSampleSize *= 2
        }
    }
    return inSampleSize
}

放弃自定义Decoder,利用Glide原生能力

自定义Decoder反而可能绕开Glide的内置优化(比如内存/磁盘缓存的自动管理、线程池调度),建议直接使用Glide的RequestOptions来指定缩略图尺寸,让Glide自动完成采样、缓存和异步加载:

// 在LazyColumn的item中加载图片
Glide.with(context)
    .load(file)
    .override(200, 200) // 指定缩略图尺寸
    .centerCrop()
    .placeholder(R.drawable.placeholder)
    .error(R.drawable.image_icon)
    .into(imageView)

同时调整ImageLoader的配置,确保Glide的缓存策略正常工作:

override fun newImageLoader(): ImageLoader {
    return GlideBuilder(this)
        .setDefaultRequestOptions(RequestOptions()
            .placeholder(R.drawable.placeholder)
            .error(R.drawable.image_icon))
        .setMemoryCache(MemoryCache.Builder(this)
            .maxSizePercent(0.25)
            .build())
        .setDiskCache(DiskCache.Builder()
            .maxSizePercent(0.25)
            .directory(cacheDir)
            .build())
        .setLogger(DebugLogger())
        .build(this)
}

LazyColumn本身的性能优化

  • 给每个列表项设置唯一的key,避免滚动时不必要的重组:
    LazyColumn {
        items(imageFiles, key = { it.path }) { file ->
            // 加载缩略图的Item布局
        }
    }
    
  • 固定列表项的高度,让LazyColumn提前计算布局,减少测量开销:
    <!-- Item布局的根布局设置固定高度 -->
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="200dp">
        <!-- 图片View -->
    </LinearLayout>
    
  • 开启列表滚动时的加载节流:使用Glide.with(context).pauseRequests()和resumeRequests()监听LazyColumn的滚动状态,滚动时暂停非可见区域的图片加载。

内容的提问来源于stack exchange,提问作者Ahsan Ali

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 21:35:20