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

Compose Desktop窗口跨屏移动时itemsIndexed出现重复项问题排查

问题解答:Compose Desktop中LazyList列表更新与重复项问题

一、关于mutableStateListOf的更新与重组机制

  • Compose的mutableStateListOf是可观察的状态容器,内部封装了列表的可变操作,当调用add()/remove()/clear()等方法修改列表内容时,会自动触发依赖该列表的UI组件重组。
  • 不需要额外同步其他状态变量,只要确保列表通过remember持有即可——remember能保证Compose重组时复用原有列表实例,而不是重新创建新的空列表。
  • 你之前用clear()+addAll()的方式也能触发重组,但直接调用mutableStateListOf的可变方法是更简洁的正确实现方式。

二、窗口跨屏移动时列表项重复的原因与解决

问题根源

你的代码中,初始项的添加逻辑直接写在App() Composable的根作用域:

val listSorted = remember { mutableStateListOf<TestObject>() }
val testObjectOne = TestObject("Test One")
val testObjectTwo = TestObject("Test Two")

listSorted.add(testObjectOne) // 每次重组都会执行
listSorted.add(testObjectTwo) // 每次重组都会执行

当窗口跨屏移动、大小调整等操作触发Composable重组时,这两行添加代码会重复执行,导致初始项被多次加入列表,最终出现重复显示的问题。

解决方法

把初始数据的添加逻辑放到remember的初始化块中,确保只在列表第一次创建时执行:

val listSorted = remember {
    mutableStateListOf<TestObject>().apply {
        add(TestObject("Test One"))
        add(TestObject("Test Two"))
    }
}

如果是更复杂的初始化逻辑(比如从本地读取数据),也可以用LaunchedEffect(Unit)实现一次性执行:

val listSorted = remember { mutableStateListOf<TestObject>() }
LaunchedEffect(Unit) {
    listSorted.add(TestObject("Test One"))
    listSorted.add(TestObject("Test Two"))
}

修正后的完整代码

TestObject.kt

data class TestObject(var testName: String)

Main.kt

import androidx.compose.desktop.ui.tooling.preview.Preview
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.material.Button
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.window.Window
import androidx.compose.ui.window.application

@Composable
@Preview
fun App() {
    var text by remember { mutableStateOf("Hello, World!") }
    // 初始化时一次性添加初始项
    val listSorted = remember {
        mutableStateListOf<TestObject>().apply {
            add(TestObject("Test One"))
            add(TestObject("Test Two"))
        }
    }

    MaterialTheme {
        Button(onClick = {
            text = "Hello, Desktop!"
            listSorted.add(TestObject("New Object"))
        }) {
            Text(text)
        }

        LazyColumn {
            itemsIndexed(listSorted) { index, item ->
                Text(item.testName)
            }
        }
    }
}

fun main() = application {
    Window(onCloseRequest = ::exitApplication) {
        App()
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 17:23:14