Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jetpack Compose - LazyColumnFor not recomposing when item added

I am trying to create a list of items in Jetpack Compose that automatically updates whenever the underlying data changes, but it is not updating and I cannot add an item to the LazyColumnFor after it has initially composed.

private var latestMessages = mutableListOf<ChatMessage>()

override fun onCreateView(
    inflater: LayoutInflater, container: ViewGroup?,
    savedInstanceState: Bundle?
): View {
    return ComposeView(context = requireContext()).apply {
        setContent {
            LatestMessages(latestMessages)
        }
    }
}

@Composable
fun LatestMessages(messages: MutableList<ChatMessage>) {
    Column {
        LazyColumnFor(items = messages) { chatMessage ->
            LatestMessageItem(chatMessage) {
                // onclick
            }
        }
    }
    Box(alignment = Alignment.Center) {
        Button(onClick = {
            latestMessages.add(
                    ChatMessage(
                            "testId",
                            "testText2",
                            "testFromId2",
                            "testToId",
                            "timestamp",
                            0
                    )
            )
        }) {

        }
    }
}

The Button in the Box is just to test adding an item. From what I understand LazyColumnFor should update whenever the underlying data is changed, similar to ForEach in SwiftUI. What am I doing wrong?

like image 688
Versicarius Avatar asked Nov 27 '20 14:11

Versicarius


1 Answers

Edit March 2022

Jetpack compose no longer uses LazyColumnFor so I've updated the answer to reflect the current state of compose.

Jetpack compose always needs a state object to be modified before recomposition can occur. You need to use a MutableStateList<T>. You can pass a reference to it around and update in any method which accepts a SnapShotStateList<T>

override fun onCreateView(
    inflater: LayoutInflater, container: ViewGroup?,
    savedInstanceState: Bundle?
): View {
    
    return ComposeView(context = requireContext()).apply {
        setContent {
            val latestMessages = mutableStateListOf<ChatMessage>()
            LatestMessages(latestMessages)
        }
    }
}

@Composable
fun LatestMessages(messages: SnapshotStateList<ChatMessage>) {
    Column {
        LazyColumn { 
            items(messages){ chatMessage ->
                LatestMessageItem(chatMessage) {
                // onclick
                }
         }
      }
    Box(alignment = Alignment.Center) {
        Button(onClick = {
            latestMessages.add(
                ChatMessage(
                    "testId",
                    "testText2",
                    "testFromId2",
                    "testToId",
                    "timestamp",
                    0
                )
            )
        }) {

        }
    }
}
like image 184
Rafsanjani Avatar answered Sep 29 '22 09:09

Rafsanjani