Jetpack Compose LazyColumn中可点击GlideImage元素的性能问题
问题根因分析
核心问题是不稳定的onClick lambda触发了大量不必要的组件重组,连带执行了耗时的IO操作,最终导致加载速度变慢:
- 你在网格项中传入的
onClicklambda为当场创建,捕获了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
相关产品推荐
相关产品推荐

