I have a simple example app that can
- Load a new list (of 2 items, with id 0 and 1, and random text for each)
- It can swipe to dismiss any item.
If I
- load the new list for the first time
- swipe to delete the first item
- load a new list (that has same ID, but different random text)
- swipe to delete the second item
It will crash as shown in the GIF below (You can get the code design from here
The reason is crashes because, upon Swipe-to-Dismiss the 2 item (of the 2nd time loaded data), the item it found is still the 2 item of the 1st time loaded data.
It does seems dismissState (as shown code below) always remember the 1st time loaded data (instead of the new data loaded)
val dismissState = rememberDismissState(
confirmStateChange = {
Log.d("Track", "$item\n${myListState.value.toMutableList()}")
viewModel.removeItem(item)
true
}
)
Hence this causes the deletion to send the wrong item in for deletion, and thus causes the failure and crash.
The complete LazyColumn and SwipeToDismiss code is as below
LazyColumn(modifier = Modifier.fillMaxHeight()) {
items(
items = myListState.value,
key = { todoItem -> todoItem.id }
) { item ->
val dismissState = rememberDismissState(
confirmStateChange = {
viewModel.removeItem(item)
true
}
)
SwipeToDismiss(
state = dismissState,
background = {
dismissState.dismissDirection ?: return@SwipeToDismiss
Box(modifier = Modifier.fillMaxSize().background(Color.Red))
},
dismissContent = {
// The row view of each item
}
)
}
}
Is this
- My issue, is that I miss out on anything to refresh the dismissState upon loading of new data?
- A Google Bug, where SwipeToDismiss will always have to work with a list of Unique IDs . Even if the list is refreshed to a new list, it cannot have the same ID that colide with any item of the previous list
- i.e. if I replace
key = { todoItem -> todoItem.id }
withkey = { todoItem -> todoItem.title }
, then it will all be good
- i.e. if I replace
CodePudding user response:
rememberDismissState()
will remember the confirmStateChange
lambda, which is part of the DismissState
. In your case, item
can change, but the lambda only captures the initial item
value, leading to the crash.
You can use rememberUpdatedState
to solve this:
val currentItem by rememberUpdatedState(item)
val dismissState = rememberDismissState(
confirmStateChange = {
viewModel.removeItem(currentItem)
true
}
)