Android Compose LazyColumn IllegalArgumentException:密钥已被使用

Rub*_*ros 13 android-jetpack-compose

我不断收到 IllegalArgumentException:密钥已被使用。如果您使用 LazyColumn/Row,请确保为每个项目提供唯一的键。

我确信我的钥匙是独一无二的。这是我的示例代码:

@Composable
fun UiComponent() {
    LazyColumn(
                verticalArrangement = Arrangement.spacedBy(12.dp),
                state = scrollState,
                reverseLayout = true
            ) {
                items(
                    items = viewmodel.messages,
                    key = { item -> item.hashcode() },
                    itemContent = { item: Entity ->
                        if (item.isDeleted) {
                            //show deleted ui
                        } else {
                            //show messages
                        }
                    })
            }
        }
}

ViewModel {

    init { 
       observeDataFromDB()
    }

    private val _messages: MutableList<Entity> = mutableStateListOf()
    val messages: List<Entity> = _messages


    fun observeDataFromDB() {
        viewModelScope.launch {
            repo.getData().collect {
                _messages.apply {
                    addNewItem(it)
                }
            }
        }
    }

}


//extensions
fun MutableList<Entity>.addNewItem(entity: Entity) {
    if (this.size >= MAX_SIZE) {
        removeLast()
    }
    Log("existing ${this.toList().map { "${it.hashCode()}" }}")
    Log("adding new ${entity.hashCode()}")
    this.add(0, entity)
}

//id is unique
data class Entity(id:String, isDeleted: Boolean, message: String)
Run Code Online (Sandbox Code Playgroud)

我也尝试从我的 Viewmodel( StateFlow<List<Entity>) 提供可观察的结果,但我得到了同样的错误。还尝试设置id为密钥。

大多数情况下在快速添加项目时会遇到此问题。例如,用户在短时间内发送多条垃圾邮件。

And*_*Dev 5

如果您的任何消息相同,您最终将得到相同的哈希码值,这将生成错误。为了避免这种情况,如果您的消息没有 id,请使用itemsIndexed而不是 justitems并将索引指定为键:

@Composable
fun UiComponent() {
    LazyColumn(
                verticalArrangement = Arrangement.spacedBy(12.dp),
                state = scrollState,
                reverseLayout = true
            ) {
                items(
                    items = viewmodel.messages,
                    key = { item -> item.id },
                    itemContent = { item: Entity ->
                        if (item.isDeleted) {
                            //show deleted ui
                        } else {
                            //show messages
                        }
                    })
            }
        }
}
Run Code Online (Sandbox Code Playgroud)