Compose 的滑动关闭状态是否始终根据 id 记住旧项目,即使列表已刷新为新项目?

Ely*_*lye 2 android android-jetpack-compose jetpack-compose-swipe-to-dismiss

我有一个简单的示例应用程序可以

  • 加载一个新列表(包含 2 个项目,id 为 0 和 1,每个项目都有随机文本)
  • 它可以滑动以消除任何项目。

如果我

  • 第一次加载新列表
  • 滑动删除第一项
  • 加载一个新列表(具有相同的 ID,但随机文本不同)
  • 滑动删除第二项

它将崩溃,如下面的 GIF 所示(您可以从这里获取代码设计https://github.com/elye/issue_android_jetpack_compose_swipe_to_dismiss_ Different_data_same_id )

在此输入图像描述

原因是崩溃,因为在滑动关闭第 2 项(第二次加载数据)时,它找到的项仍然是第一次加载数据的第 2 项。

似乎解雇状态(如下面的代码所示)总是记住第一次加载的数据(而不是加载的新数据)

                val dismissState = rememberDismissState(
                    confirmStateChange = {
                        Log.d("Track", "$item\n${myListState.value.toMutableList()}")
                        viewModel.removeItem(item)
                        true
                    }
                )
Run Code Online (Sandbox Code Playgroud)

因此,这会导致删除发送错误的项目进行删除,从而导致失败和崩溃。

完整的LazyColumn和SwipeToDismiss代码如下

       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
                    }
                )
            }
        }
Run Code Online (Sandbox Code Playgroud)

这是

  1. 我的问题是,我在加载新数据时错过了刷新 DismissState 的任何内容吗?
  2. 一个 Google Bug,其中 SwipeToDismiss 始终必须使用唯一 ID 列表。即使列表刷新为新列表,它也不能与前一个列表的任何项目具有相同的 ID
    • 即如果我替换key = { todoItem -> todoItem.id } key = { todoItem -> todoItem.title },那么一切都会好的

H.D*_*.D. 6

rememberDismissState()会记住confirmStateChangelambda,它是DismissState. 在你的情况下,item可以改变,但 lambda 只捕获初始item值,导致崩溃。

您可以使用以下方法rememberUpdatedState来解决这个问题:

val currentItem by rememberUpdatedState(item)
val dismissState = rememberDismissState(
    confirmStateChange = {
        viewModel.removeItem(currentItem)
        true
    }
)
Run Code Online (Sandbox Code Playgroud)