如何在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
相关产品推荐
相关产品推荐

