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

Jetpack Compose加载专辑封面致LazyColumn滚动卡顿问题求助

解决LazyColumn加载专辑封面滚动卡顿问题

问题根源

你当前的实现存在两个核心性能问题:

  1. 主线程阻塞:getAlbumArt函数在主线程执行MediaMetadataRetriever的IO操作和Bitmap解码,直接阻塞UI线程,导致列表滚动卡顿。
  2. 未利用Coil核心能力:手动提前获取Bitmap并传给AsyncImage,完全绕过了Coil的后台加载、缓存复用机制,将性能压力全部抛给主线程。

优化方案

1. 让Coil接管封面加载流程

移除手动调用getAlbumArt,通过自定义Coil Decoder,让Coil在后台线程完成专辑封面的提取、解码和缓存。

自定义Coil Decoder

创建专门处理音频Uri嵌入式封面的Decoder:

class AlbumArtDecoder private constructor(
    private val source: Source,
    private val context: Context
) : Decoder {

    override suspend fun decode(): DecodeResult {
        val uri = source.data as Uri
        val mmr = MediaMetadataRetriever()
        return try {
            mmr.setDataSource(context, uri)
            val embeddedPicture = mmr.embeddedPicture
            val bitmap = embeddedPicture?.let {
                BitmapFactory.decodeByteArray(it, 0, it.size)
            } ?: BitmapFactory.decodeResource(context.resources, R.drawable.default_album_art)
            DecodeResult.Source(bitmap.toImageBitmap())
        } finally {
            mmr.release()
        }
    }

    class Factory(private val context: Context) : Decoder.Factory {
        override fun create(result: Result, options: Options): Decoder? {
            val data = result.data
            return if (data is Uri && data.scheme == "content") {
                AlbumArtDecoder(result.source, context)
            } else {
                null
            }
        }
    }
}

初始化Coil加载器

在Application类中配置Coil,添加自定义Decoder:

class MyMusicApp : Application() {
    override fun onCreate() {
        super.onCreate()
        ImageLoader.Builder(this)
            .components {
                add(AlbumArtDecoder.Factory(this@MyMusicApp))
            }
            .memoryCachePolicy(CachePolicy.ENABLED)
            .diskCachePolicy(CachePolicy.ENABLED)
            .build()
            .also { Coil.setImageLoader(it) }
    }
}

2. 修改MusicRow实现

简化AsyncImage用法,直接传入音频Uri,让Coil自动处理加载:

@Composable
fun MusicRow(music: Music) {
    Row(
        modifier = Modifier
            .clickable {
                // TODO: 处理点击事件
            }
            .fillMaxWidth()
            .height(72.dp)
            .padding(vertical = 8.dp, horizontal = 16.dp)
    ) {
        Box(modifier = Modifier.clip(RoundedCornerShape(5.dp))) {
            AsyncImage(
                model = music.imagePath ?: R.drawable.default_album_art,
                placeholder = painterResource(R.drawable.default_album_art),
                contentDescription = "专辑封面",
                contentScale = ContentScale.Crop,
                modifier = Modifier
                    .size(56.dp) // 固定大小,减少布局计算开销
                    .aspectRatio(1f),
                imageLoader = LocalImageLoader.current
            )
        }

        Column(
            modifier = Modifier
                .fillMaxWidth()
                .padding(start = 16.dp)
                .align(Alignment.CenterVertically)
        ) {
            Text(
                text = music.title,
                style = MaterialTheme.typography.bodyLarge,
                maxLines = 1
            )
            Spacer(modifier = Modifier.height(4.dp))
            Text(
                text = music.artist,
                style = MaterialTheme.typography.bodyMedium,
                maxLines = 1
            )
        }
    }
}

3. 优化LazyColumn的Item复用

使用items直接传入数据源,而非通过索引获取,让LazyColumn更好地利用Compose的稳定项优化:

LazyColumn(
    modifier = Modifier.consumeWindowInsets(innerPadding),
    contentPadding = innerPadding
) {
    items(listMusic) { music ->
        MusicRow(music)
    }
}

4. 确保数据类稳定性

让Music类成为稳定类型,帮助Compose判断何时需要重组:

@Stable
data class Music(
    val title: String,
    val artist: String,
    val imagePath: Uri?
)

优化效果

  • 所有封面加载、解码操作都在Coil后台线程执行,主线程不再阻塞,滚动流畅度大幅提升。
  • 利用Coil的内存和磁盘缓存机制,重复加载同一封面时直接取缓存,减少重复IO和解码开销。
  • 固定图片尺寸、优化LazyColumn复用逻辑,进一步降低布局和重组开销。

内容的提问来源于stack exchange,提问作者Mehedi Hasan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 21:59:54