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

使用MutableStateFlow与Compose时遇ConcurrentModificationException如何解决?

解决MutableStateFlow并发修改异常的方案

问题根源

你的ConcurrentModificationException本质是可变集合的并发读写冲突:

  • 如果SearchState中的currentItems是MutableList这类可变集合,当后台线程的Callback更新状态时,Compose正同时在主线程遍历该集合,就会触发异常。
  • 数据类的默认copy()方法对集合是浅拷贝,新旧状态会共享同一个可变集合实例,后续修改会直接影响正在使用的旧状态。

具体解决步骤

1. 使用不可变集合,切断共享引用

把currentItems的类型改为不可变集合(比如List),每次更新时创建新的不可变实例:

// 定义SearchState时指定不可变集合类型
data class SearchState(val currentItems: List<SearchRowItemData> = emptyList())

// ViewModel中更新状态时,将传入的items转为不可变List
searchState.value = searchState.value.copy(
    currentItems = items.toList() // 强制转为不可变集合,避免共享可变引用
)

2. 强制在主线程更新StateFlow

MutableStateFlow的value更新本身线程安全,但跨线程更新可变状态容易引发UI侧的并发问题。确保状态更新操作在主线程执行:

private fun getItems() = viewModelScope.launch {
    ....
    object : Callback<Results> {
        override fun publish(items: Results): Boolean {
            // 切换到主线程更新状态
            viewModelScope.launch(Dispatchers.Main) {
                searchState.value = searchState.value.copy(
                    currentItems = items.toList()
                )
            }
            return true
        }
    }
}

3. 遍历前获取集合快照(可选兜底方案)

如果无法避免使用可变集合,在Compose遍历前先获取集合的快照,避免遍历过程中集合被修改:

@Composable
fun ScreenContent(viewModel: SearchViewModel) {
    val state by viewModel.searchState.collectAsState()
    // 先获取集合快照再遍历
    val itemsSnapshot = state.currentItems.toList()

    Column(modifier = Modifier.fillMaxWidth()) {
        itemsSnapshot.forEachIndexed { index, searchRowItemData ->
            SearchRowItem(
                searchRowItemData,
                index == itemsSnapshot.lastIndex
            ) {
                onItemClicked(searchRowItemData)
            }
        }
    }
}

4. 确认Callback的执行线程

检查你的Callback的publish方法是否在后台线程运行,如果是,必须切换到主线程更新状态——Compose的重组和UI操作都在主线程,跨线程操作可变状态是并发问题的常见诱因。

内容的提问来源于stack exchange,提问作者P.Juni

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 21:22:36