Jetpack Compose:当带有 GlideImage 的元素在 LazyColumn 中可点击时出现性能问题
Jetpack Compose: Performance problem when element with GlideImage is clickable in LazyColumn
我有带 LazyColumn 的 VideoListScreen,我使用 VideoItem 作为我的项目。这个 LazyColumn 它是用网格项创建的,以具有类别 header 的惰性网格视图。标签是类别的标签。 Category details是关于类别颜色、标题等的信息:
@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() )
}
}
VideoListScreen:
@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”。
如有任何问题,欢迎随时提问!
在 compose 中,您正在使用视图构建器创建 UI。这个函数可以多次调用,当你开始使用动画时,它甚至可以在每一帧上重新组合。
这就是为什么您不应该直接在可组合函数中执行任何繁重的工作。如果你这样做,你需要存储结果,这样你就不需要在下一次重组时重新计算。
fetchVideos
和 assets.open
都是相当繁重的操作,甚至 getCategoryDetailsBy
(不知道那是什么)的结果也应该被缓存。为此,您需要使用 remember
或 rememberSaveable
。查看这些有何不同以及更多关于 state in composables.
所以像这样更新你的声明:
val categoryDetails = remember { getCategoryDetailsBy(tag) }
val videos = remember { fetchVideos(context, tag) }
val context = LocalContext.current
val assetFileDescriptor = remember { context.assets.open(videoPath) }
我有带 LazyColumn 的 VideoListScreen,我使用 VideoItem 作为我的项目。这个 LazyColumn 它是用网格项创建的,以具有类别 header 的惰性网格视图。标签是类别的标签。 Category details是关于类别颜色、标题等的信息:
@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() )
}
}
VideoListScreen:
@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”。
如有任何问题,欢迎随时提问!
在 compose 中,您正在使用视图构建器创建 UI。这个函数可以多次调用,当你开始使用动画时,它甚至可以在每一帧上重新组合。
这就是为什么您不应该直接在可组合函数中执行任何繁重的工作。如果你这样做,你需要存储结果,这样你就不需要在下一次重组时重新计算。
fetchVideos
和 assets.open
都是相当繁重的操作,甚至 getCategoryDetailsBy
(不知道那是什么)的结果也应该被缓存。为此,您需要使用 remember
或 rememberSaveable
。查看这些有何不同以及更多关于 state in composables.
所以像这样更新你的声明:
val categoryDetails = remember { getCategoryDetailsBy(tag) }
val videos = remember { fetchVideos(context, tag) }
val context = LocalContext.current
val assetFileDescriptor = remember { context.assets.open(videoPath) }