Since LazyVerticalGrid does not support span for h...
# compose
t
Since LazyVerticalGrid does not support span for headers I'm trying to use a LazyColumn with Grid and windowed on the list. Since I need fixed counts the elements have all weight(1f) and aspectRatio() for some part of the content but performance is not great at all. Is there something more efficient than the weight or anything I can do to hint the LazyColumn that all rows will have the same height to improve perf?
a
LazyVerticalGrid internally using LazyColumn with Rows with weight on elements and we don’t see any performance issues. Could you please clarify why do you think weight is affecting the performance?
t
Completely random guess from profiler and previous experience, when you see large measure part. Don't really know how to properly analyse the compose part, was actually simpler in view world.
a
most likely the issue is that you need to do recompositions on every scroll offset. can you please show the code?
t
I made tons of different test but here's one version:
Copy code
val items = remember(lazyPagingItems.itemCount) {
                            derivedStateOf {
                                List(lazyPagingItems.itemCount) { it }.windowed(stepSize, stepSize, true)
                            }
                        }
						
						
LazyColumn(
	state = lazyListState,
	contentPadding = PaddingValues(vertical = 8.dp),
	content = {
		item {
			Header(viewModel)
		}
		items(items.value) { items ->
			Row(
				modifier = Modifier
					.fillMaxWidth()
					.padding(horizontal = 4.dp)
			) {
				items.map { lazyPagingItems[it] }.forEach {
					AlbumEntryGrid(it, viewModel.getThumbnailImagePath(it)) {
						if (it != null) {
							navigator.navigateTo(AlbumDetailsScreenDestination(it))
						}
					}
				}
				repeat(stepSize - items.size) {
					Spacer(modifier = Modifier.weight(1f))
				}
			}
		}
	}
)						
								
@Composable
fun RowScope.AlbumEntryGrid(mediaItem: MediaItem?, thumbnailImagePath: ImagePath, onRowClick: () -> Unit) {
    val finalMediaItem = mediaItem ?: MediaItem(title = "Placeholder")
    Box(
        Modifier
            .clickable { onRowClick() }
            .aspectRatio(1f)
            .weight(1f)
            .padding(4.dp)
            .clip(RoundedCornerShape(8.dp)),
    ) {
        val imageRequest = ImageRequest(
            thumbnailImagePath,
            exactSize = false,
            debugTag = "AlbumEntryGrid"
        )
        Image(
            imageRequestPainter = rememberImageRequestPainter(imageRequest = imageRequest),
            contentDescription = null,
            error = @Composable { Error(finalMediaItem) },
            placeHolder = @Composable { SurfacePlaceHolder() },
            contentScale = ContentScale.FillBounds,
            modifier = Modifier
                .aspectRatio(1f)
        )
    }
}
Logging composition count I do not see extra composition ocurring. 1 time the lazyColum and 3 times each item for the 3 image states. Only thing that is strange is that despite the itemcount not changing.
Copy code
remember(lazyPagingItems.itemCount) {
                            derivedStateOf {
                                List(lazyPagingItems.itemCount) { it }.windowed(stepSize, stepSize, true)
                            }
                        }
Is triggering a recalculation of the derived state and so the tree when compose paging load a new page. (But the perf issue is also ocutring when all pages are loaded so it's not the root cause). Is there something wrong with that approach to have a stable state that contains a list of number that must only be recreated when the actual itemcount change ?
a
do you use lazyListState somewhere else? not in the code you already shared
t
Nope a simple
Copy code
val lazyListState = rememberLazyListState()
It's just defined earlier as I use the same when switching from list to grid
But as said I'm using :
Copy code
@Composable
inline fun LogCompositions(tag: String) {
    if (ENABLE_DEBUG_COMPOSITION_LOGS && BuildConfig.DEBUG) {
        val ref = remember { Ref(0) }
        SideEffect {
            ref.value++
            Logger.logger.logError(tag, "Compositions: ${ref.value}", null, true)
        }
    }
}
To check on extra composition and each item is only composed 3 times as the image state goes from empty to loading to success / error
Anyway it's very late here, but thanks for confirming that the row + weight should work and I need to try to figure out where the issue is, but it's not a wrong approach to my problem.
@Andrey Kulikov After doing some tests this seems like a regression from Compose 1.1
Copy code
val items = List(14000) { listOf(it, it, it) }
                LazyColumn(
                    state = rememberLazyListState(),
                    content = {
                        items(items) { items ->
                            Row(
                                modifier = Modifier
                                    .fillMaxWidth()
                                    .padding(4.dp)
                                    .background(Color.Red)
                            ) {
                                items.forEach {
                                    Surface(
                                        color = Color.DarkGray,
                                        modifier = Modifier
                                            .clickable { /*onRowClick()*/ }
                                            .weight(1f)
                                            .aspectRatio(5f)
                                            .padding(4.dp)) {}
                                }
                            }
                        }
                    }
                )
This in a new default compose activity just updated to compose 1.1 will be insanely slow
HWUI overlay looks like this for this simple when scrolling.