I have a ViewModel that produces a StateFlow like this:
private val _profiles = MutableStateFlow<List<ProfileSnap>>(listOf())
val profiles: StateFlow<List<ProfileSnap>>
get() = _profiles
Values are updated in another fun:
private fun loadProfiles() = viewModelScope.launch {
_profiles.value = profileDao.getAll(profilesSearch, profilesSort)
}
Finally, in Compose I list all values (this is a simplified version of my code):
@Composable
fun SetContent(viewModel: ProfilesViewModel){
val profiles = viewModel.profiles.collectAsState()
LazyColumn(
modifier = Modifier
.fillMaxHeight()
) {
itemsIndexed(items = profiles.value) { _, profile ->
Text(
text = "(${profile.profileId}) ${profile.label}",
modifier = Modifier
.pointerInput(Unit) {
detectTapGestures(
onLongPress = {
Log.d(TAG, "onLongPress: ${profile.profileId}")
},
onTap = {
Log.d(TAG, "onTap: ${profile.profileId}")
},
)
}
)
}
}
}
At the beginning, when I reach the list fragment and I click on an element, I get the correct corresponding profileId. But, when I apply a filter or I change the list sorting and the loadProfiles() function is called:
What am I doing wrong? profiles are not up to date? But if they are not updated, why the list is "graphically" correct? Here what happens:
(1) A
-----
(2) B
-----
(3) C <== CLICK - onTap: 3 / LONGPRESS - onLongPress: 3
Change sort order:
(3) C
-----
(2) B
-----
(1) A <== CLICK - onTap: 3 [should has been 1] / LONGPRESS - onLongPress: 3 [should has been 1]
Thank you very much
You can check 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:
LazyColumn() {
items(
items = profiles.value,
key = { profile ->
// Return a stable + unique key for the item
profile.profileId
}
) { profile ->
//....
}
}