Sunday 29 November 2020

Jetpack Compose model list becomes jumbled when adding new items

I have an issue with Jetpack compose displaying a model containing a ModelList of items. When new items are added, the order of the UI elements becomes incorrect.

Here's a very simple CounterModel containing a ModelList of ItemModels:

@Model
data class CounterModel(
    var counter: Int = 0,
    var name: String = "",
    val items: ModelList<ItemModel> = ModelList()
)

@Model
data class ItemModel(
    var name: String
)

The screen shows two card rows for each ItemModel: RowA and RowB. When I create this screen initialised with the following CounterModel:

val model = CounterModel()
model.name="hi"
model.items.add(ItemModel("Item 1"))
model.items.add(ItemModel("Item 2"))
CounterModelScreen(model)

...it displays as expected like this:

Item 1 Row A

Item 1 Row B

Item 2 Row A

Item 2 Row B

When I click my 'add' button, to insert a new ItemModel, I simply expect to see

Item 3 Row A

Item 3 Row B

At the bottom. But instead, the order is jumbled, and I see two rowAs then two rowBs:

Item 1 Row A

Item 1 Row B

Item 2 Row A

Item 3 Row A

Item 3 Row B

Item 2 Row B

I don't really understand how this is possible. The UI code is extremely simple: loop through the items and emit RowA and RowB for each one:

for (i in counterModel.items.indices) {
    RowA(counterModel, i)
    RowB(counterModel, i)
}

Using Android Studio 4.0C6

Here's the complete code:

@Composable
fun CounterModelScreen(counterModel: CounterModel) {
    Column {
        TopAppBar(title = {
            Text(
                text = "Counter Model"
            )
        })

        CounterHeader(counterModel)
        for (i in counterModel.items.indices) {
            RowA(counterModel, i)
            RowB(counterModel, i)
        }
        Button(
            text = "Add",
            onClick = {
                counterModel.items.add(ItemModel("Item " + (counterModel.items.size + 1)))
            })
    }
}

@Composable
fun CounterHeader(counterModel: CounterModel) {
    Text(text = counterModel.name)
}

@Composable
fun RowA(counterModel: CounterModel, index: Int) {
    Padding(padding = 8.dp) {
        Card(color = Color.White, shape = RoundedCornerShape(4.dp)) {
            Column(crossAxisSize = LayoutSize.Expand) {
                Text(
                    text = counterModel.items[index].name
                )
                Text(text = "Row A")
            }
        }
    }
}

@Composable
fun RowB(counterModel: CounterModel, index: Int) {
    Padding(padding = 8.dp) {
        Card(color = Color.Gray, shape = RoundedCornerShape(4.dp)) {
            Column(crossAxisSize = LayoutSize.Expand) {
                Text(
                    text = counterModel.items[index].name
                )
                Text(text = "Row B")
            }
        }
    }
}


from Jetpack Compose model list becomes jumbled when adding new items

No comments:

Post a Comment