You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Compose侧滑删除状态因重复ID保留旧数据是否会导致崩溃?

Jetpack Compose SwipeToDismiss 重复ID列表崩溃问题分析

问题场景

应用功能

  • 加载包含2个项的新列表(项ID固定为0和1,每项带随机文本)
  • 支持侧滑删除任意列表项

触发崩溃的操作步骤

  1. 首次加载新列表
  2. 侧滑删除第一个项(ID=0)
  3. 加载新列表(项ID仍为0和1,但文本为新的随机值)
  4. 侧滑删除第二个项(ID=1)→ 应用崩溃

崩溃原因

侧滑删除第二次加载的ID=1项时,实际操作的是第一次加载的ID=1项,导致调用viewModel.removeItem(item)时,传入的旧item对象不存在于新列表中,引发崩溃。

关键代码中的问题点:

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

rememberDismissState会记住首次加载时捕获的旧item对象,即使列表刷新为新数据,只要项ID未变,Compose会复用之前的组件状态,导致回调里的item始终是旧数据。

完整的LazyColumn实现:

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 = {
                // 列表项的行布局
            }
        )
    }
}

问题解答

  1. 这是代码问题:你没有让rememberDismissState感知到列表项的更新。当列表刷新后,ID相同的项被Compose视为同一个组件,复用了旧的dismissState,而该状态里的item还是旧数据。
  2. 不是Google框架Bug:SwipeToDismiss允许列表项ID重复,但需要确保组件状态与当前的列表项数据绑定。你改用key = { todoItem -> todoItem.title }后正常,是因为每次新列表的title都是随机值,每个项的key唯一,Compose会创建新的组件和对应的dismissState,此时捕获的item是最新的。

解决方案

方案一:调整列表项的key,确保唯一标识当前实例

结合ID和内容生成唯一key,让Compose在数据更新时重新创建组件和状态:

items(
    items = myListState.value,
    key = { todoItem -> "${todoItem.id}-${todoItem.title.hashCode()}" }
) { item ->
    // 后续代码不变
}

方案二:让dismissState依赖当前item,数据更新时重建状态

通过remember包裹DismissState,指定依赖项为item,确保数据变化时重新创建状态:

val dismissState = remember(item) {
    DismissState(
        confirmStateChange = {
            viewModel.removeItem(item)
            true
        }
    )
}

内容的提问来源于stack exchange,提问作者Elye

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 04:16:08