Reputation: 4221
Can someone explain me what's the main purpose of the 'key' parameter inside items/itemsIndexed function of LazyListScope? What do we get or don't get if we specify that parameter? I'm not sure that I understand the official docs related to this parameter:
key - a factory of stable and unique keys representing the item. Using the same key for multiple items in the list is not allowed. Type of the key should be saveable via Bundle on Android. If null is passed the position in the list will represent the key. When you specify the key the scroll position will be maintained based on the key, which means if you add/remove items before the current visible item the item with the given key will be kept as the first visible one.
Upvotes: 20
Views: 20477
Reputation: 912
distinct
as:The instance of a composable in Composition is identified by its call site. The Compose compiler considers each call site as distinct. Calling composables from multiple call sites will create multiple instances of the composable in Composition.
call site : is the source code location in which a composable is called. This influences its place in Composition, and therefore, the UI tree
distinct
if it is called in different spots in your code, even if the composables are the same:Column {
YourComposable()
YourComposable()
}
Both instance of YourComposable()
are considered distinct
by the compiler
So if a composable is distinct
(called from different places in your code) the compose compiler will know to only recompose the composable that has a state change
However, what happens when you have a for loop like this:
@Composable
fun MoviesScreen(movies: List<Movie>) {
Column {
for (movie in movies) {
// MovieOverview composables are placed in Composition given its
// index position in the for loop
MovieOverview(movie)
}
}
}
MovieOverview
is being called from the same call site
(not distinct). To combat this scenario the compose compiler will use the execution order in addition to the call site to keep the instances distinct
This will work fine as long as values are only removed and added to the bottom of the list(index of length-1). But once the list changes by either adding to the top or the middle of the list. Or by removing or reordering items ,it'll cause a recomposition in all MovieOverview calls whose input parameter has changed position in the list
if you have a list of length 100 and you insert at item at index 50, then all the composables from index 99-50 will get recomposed even though they have not had their state changed
@Composable
fun MoviesScreenWithKey(movies: List<Movie>) {
Column {
for (movie in movies) {
key(movie.id) { // Unique ID for this movie
MovieOverview(movie)
}
}
}
}
@Composable
fun MoviesScreenLazy(movies: List<Movie>) {
LazyColumn {
items(movies, key = { movie -> movie.id }) { movie ->
MovieOverview(movie)
}
}
}
key
and tried to remove, add or reorganize we would face the exact same wasteful recompositions mention earlierLifecycle of composables documentation
Upvotes: 5
Reputation: 12222
you can use this way
@Composable
fun A(list: MutableList<Model>) {
Column {
LazyColumn {
items(
count = list.size,
key = {
list[it].id
}, itemContent = { index ->
Text(text = list[index].text)
}
)
}
}
}
Upvotes: -1
Reputation: 363439
I think the best answer is provided by the official doc:
By default, each item's state is keyed against the position of the item in the list. However, this can cause issues if the data set changes, since items which change position effectively lose any remembered state. If you imagine the scenario of
LazyRow
within aLazyColumn
, if the row changes item position, the user would then lose their scroll position within the row.
To combat this, you can provide a stable and unique key for each item, providing a block to the
key
parameter. Providing a stable key enables item state to be consistent across data-set changes:
@Composable
fun MessageList(messages: List<Message>) {
LazyColumn {
items(
items = messages,
key = { message ->
// Return a stable + unique key for the item
message.id
}
) { message ->
MessageRow(message)
}
}
}
Upvotes: 33