首页 > 解决方案 > Jetpack Compose:当带有 GlideImage 的元素在 LazyColumn 中可点击时出现性能问题

问题描述

我有带有 LazyColumn 的 VideoListScreen,我使用 VideoItem 作为我的项目。这个 LazyColumn 它是使用网​​格项创建的,具有带有类别标题的惰性网格视图。标签是类别的标签。类别详细信息是有关类别颜色、标题等的信息:

@Composable
fun VideoItem(
    videoPath: String,
    brush: Brush,
    modifier: Modifier = Modifier,
    onClick: () -> Unit
) {
    val assetFileDescriptor = LocalContext.current.assets.open(videoPath)
    Surface(
        modifier = modifier
            .padding(5.dp)
            .aspectRatio(1f)
            .clickable { onClick() },
        shape = Shapes.small,
        elevation = 1.dp
    ) {
        GlideImage(
            imageModel = assetFileDescriptor.readBytes(),
            contentScale = ContentScale.Crop,
            requestOptions = RequestOptions.diskCacheStrategyOf(DiskCacheStrategy.NONE),
            shimmerParams = ShimmerParams(
                baseColor = MaterialTheme.colors.background,
                highlightColor = Blue200,
                durationMillis = 650,
                dropOff = 0.65f,
                tilt = 20f
            )
        )
        Box(modifier = Modifier
            .background(brush)
            .fillMaxSize() )
    }
}

视频列表屏幕:

@Composable
fun VideoListScreen(
    navController: NavHostController,
    tag: String
) {
    val cells = 2
    val context = LocalContext.current
    val categoryDetails = getCategoryDetailsBy(tag)
    val videos = fetchVideos(context, tag)
    LazyColumn(contentPadding = PaddingValues(5.dp)) {
        item {
            CategoryElement(
                categoryDetails = categoryDetails,
                modifier = Modifier
                    .fillMaxWidth()
                    .height(130.dp)
                    .padding(5.dp),
                customTitle = "O kategorii"
            )
        }
        gridItems(videos, cells) { assetFileName ->
            val videoPath = "$tag/$assetFileName"
            VideoItem(
                videoPath = videoPath,
                brush = categoryDetails.transparentBrush
            ) { navController.navigateToPlayer(videoPath) } //onClick function
        }
    }
}

private fun fetchVideos(context: Context, tag: String): List<String> {
    return context.resources.assets.list("$tag/")?.toList() ?: listOf()
}

gridItems 扩展功能:

    fun <T> LazyListScope.gridItems(
    data: List<T>,
    cells: Int,
    itemContent: @Composable BoxScope.(T) -> Unit,
) {
    items(data.chunked(cells)) { row ->
        Row(Modifier.fillMaxWidth()) {
            for ((index, item) in row.withIndex()) {
                Box(Modifier.fillMaxWidth(1f / (cells - index))) {
                    itemContent.invoke(this, item)
                }
            }
        }
    }
}

问题是,当我尝试在此项目上应用可点击性时(无论在哪里),缩略图加载(从资产)变得几乎两倍慢。当 onClick 函数为空时,有趣的是,性能问题消失了。在名为“navigateToPlayer(videoPath)”的函数中,我导航到另一个屏幕并使用 navController 发送“videoPath”。

如果您有任何问题随时问!

标签: androidkotlinandroid-jetpackandroid-jetpack-compose

解决方案


在 compose 中,您正在使用视图构建器创建 UI。这个函数可以多次调用,当你开始使用动画时,它甚至可以在每一帧上重新组合。

这就是为什么你不应该直接在可组合函数中执行任何繁重的工作。如果你这样做了,你需要存储结果,这样你就不需要在下一次重组时重新计算。

两者fetchVideosassets.open都是相当繁重的操作,甚至getCategoryDetailsBy应该缓存(不确定那是什么)的结果。为此,您需要使用rememberor rememberSaveable。看看这些有什么不同以及更多关于可组合物中的状态

因此,像这样更新您的声明:

val categoryDetails = remember { getCategoryDetailsBy(tag) }
val videos = remember { fetchVideos(context, tag) }

val context = LocalContext.current
val assetFileDescriptor = remember { context.assets.open(videoPath) }

推荐阅读