A very very simple example (implementation(platform("androidx.compose:compose-bom:2023.08.00"))):
package com.study.myapplication
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import com.study.myapplication.ui.theme.MyApplicationTheme
data class Id(val level: Int, val index: Int)
class Man(val id: Id, val name: String)
val men = listOf(
Man(Id(1, 1), "Amy"),
Man(Id(1, 2), "Bob")
)
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MyApplicationTheme {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
Greeting(men)
}
}
}
}
}
@Composable
fun Greeting(men: List<Man>, modifier: Modifier = Modifier) {
LazyColumn (modifier = modifier) {
items(men, key = { it.id.index }) { // <- render problem
//items(men, key = { it.id }) { // <- okay
Text(it.name)
}
}
}
@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
MyApplicationTheme {
Greeting(men)
}
}
Refer to the comments in the code: If I use man.Id.index as key, it renders ok. If I use man.Id as key, it prompts render problem.
In a physic device, I found the real reason:
java.lang.IllegalArgumentException: Type of the key Id(level=1, index=1) is not supported. On Android you can only use types which can be stored inside the Bundle.
Why?
When you use it.id.index
as the key, you're essentially using an Int
value, which is a primitive type that can be easily stored in a Bundle
. But, when you use it.id
, you're trying to use a custom data class
id
, which cannot be directly stored in a Bundle
because it's not a primitive type nor a type that implements Parcelable
.
So If needed, you can utilize Parcelable
.
@Parcelize
data class Id(val level: Int, val index: Int): Parcelable
do not forget add kotlin-parcelize
plugin to build.gradle
plugins {
id("kotlin-parcelize")
}