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

Jetpack Compose LazyColumn中可点击GlideImage元素的性能问题

问题根因分析

核心问题是不稳定的onClick lambda触发了大量不必要的组件重组,连带执行了耗时的IO操作,最终导致加载速度变慢:

  • 你在网格项中传入的onClick lambda为当场创建,捕获了navController和videoPath两个参数,默认会被Compose编译器判定为不稳定类型。只要上层发生重组,lambda就会重新生成,触发VideoItem跟随重组。
  • 空onClick属于无捕获的稳定lambda,不会触发额外重组,所以性能问题消失。
  • VideoItem中直接在组合阶段执行assetFileDescriptor.readBytes(),每次重组都会重复读取assets文件,叠加你关闭了Glide磁盘缓存,每次重组都会重复加载图片,耗时直接翻倍。
  • 额外冗余:fetchVideos没有加缓存,每次VideoListScreen重组都会重新遍历assets目录。
修复方案
  • 缓存onClick lambda,保证只有依赖参数变化时才重新创建
    修改VideoListScreen中网格项的调用逻辑:
    gridItems(videos, cells) { assetFileName ->
        val videoPath = "$tag/$assetFileName"
        // 用remember缓存点击事件,仅当videoPath或navController变化时才重新生成
        val onClick = remember(videoPath, navController) {
            { navController.navigateToPlayer(videoPath) }
        }
        VideoItem(
            videoPath = videoPath,
            brush = categoryDetails.transparentBrush,
            onClick = onClick
        )
    }
    
  • 把VideoItem中的文件读取逻辑从组合阶段移到缓存逻辑中,避免重复IO
    修改VideoItem代码:
    @Composable
    fun VideoItem(
        videoPath: String,
        brush: Brush,
        modifier: Modifier = Modifier,
        onClick: () -> Unit
    ) {
        val context = LocalContext.current
        // 仅当videoPath变化时才重新读取文件字节
        val videoBytes by remember(videoPath) {
            mutableStateOf(context.assets.open(videoPath).readBytes())
        }
        Surface(
            modifier = modifier
                .padding(5.dp)
                .aspectRatio(1f)
                .clickable(onClick = onClick),
            shape = Shapes.small,
            elevation = 1.dp
        ) {
            GlideImage(
                imageModel = videoBytes,
                contentScale = ContentScale.Crop,
                // 开启内存缓存,避免重复解码图片
                requestOptions = RequestOptions()
                    .diskCacheStrategy(DiskCacheStrategy.NONE)
                    .skipMemoryCache(false),
                shimmerParams = ShimmerParams(
                    baseColor = MaterialTheme.colors.background,
                    highlightColor = Blue200,
                    durationMillis = 650,
                    dropOff = 0.65f,
                    tilt = 20f
                )
            )
            Box(modifier = Modifier.background(brush).fillMaxSize())
        }
    }
    
  • 缓存视频列表数据,避免重复遍历assets
    修改VideoListScreen中视频列表的读取逻辑:
    val videos by remember(tag, context) {
        mutableStateOf(fetchVideos(context, tag))
    }
    
  • 可选优化:给VideoItem的所有参数添加@Immutable/@Stable注解,进一步降低重组概率。

内容的提问来源于stack exchange,提问作者Arkadiusz Mądry

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 13:39:03