Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android Compose LazyColumn IllegalArgumentException: Key was already used

I keep getting IllegalArgumentException: Key was already used. If you are using LazyColumn/Row please make sure you provide a unique key for each item.

I am sure my keys are unique. Here is my sample code:

@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)

I have also tried providing an observable from my Viewmodel(StateFlow<List<Entity>) but I get the same error. Also tried setting id as the key.

Mostly encountering this issue when items are rapidly added. For example user spamming multiple messages in a short time.

like image 609
Ruben Quadros Avatar asked Nov 29 '25 20:11

Ruben Quadros


2 Answers

If any of your messages are identical, you'll end up with the same hashcode value and this will generate the error. To avoid this, if your messages don't have an id, use itemsIndexed instead of just items and assign the index as the key:

@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
                        }
                    })
            }
        }
}
like image 77
Johann Avatar answered Dec 04 '25 22:12

Johann


If anyone is facing similar issue:

For me it got resolved after removing mutableStateListOf and using a simple list and observing this list in composable as state.

Basically StateFlow<List< Entity>> and in compose viewmodel.message.collectAsState(). Finally passing this list to the lazyColumn

like image 26
Ruben Quadros Avatar answered Dec 04 '25 20:12

Ruben Quadros