My composable view doesn't recompose itself even though state changes

Viewed 1369

I am trying to develop sample chat app with jetpack compose and struggling with states. I have lazyColumn which contains messages. My problem is when user clicks the button, my "ChatList" function doesn't recompose eventhough my list gets update. It only recompose when "message" state changes. So i can see previously added messages on list after i type something to texxtfield.

Here is my composables and viewmodel :

@Composablefun ChatList() {
ConstraintLayout {
    val (list, send) = createRefs()
    val viewModel = viewModel<MainViewModel>()
    val chatList by viewModel.messages.observeAsState(viewModel.messageList)
    var message by rememberSaveable { mutableStateOf("") }
    val state = rememberLazyListState()
    LazyColumn(state = state, modifier = Modifier.constrainAs(list) {
        top.linkTo(parent.top)
        bottom.linkTo(send.top)
        height = Dimension.fillToConstraints
    }) {
        items(chatList) { item ->
            when (item.isMe) {
                true -> ChatLayoutMe(item.message)
                false -> ChatLayout(item.message)
            }
        }
    }
    SendMessage(message = message, modifier = Modifier.constrainAs(send) {
        bottom.linkTo(parent.bottom)
    }) {
        message = it
    }
}}

@Composablefun SendMessage(message: String, modifier: Modifier, onMessageChange: (String) -> Unit) {
    ......
    Column(
        modifier = Modifier
            .clickable { viewModel.addMessage(message) }
        ......    
}

class MainViewModel : ViewModel() {

  val messages = MutableLiveData<List<ChatItem>>()

  val messageList = mutableListOf<ChatItem>().apply {
    ............
  }

  fun addMessage(message: String) {
     messageList.add(ChatItem(message, true))
     messages.value = messageList
  }
}
2 Answers

I guess your the messageList property is getting the same instance of the same memory address (This won't be able to - trigger - notify new data). Try changing the code inside the addMessage function to:

fun addMessage(message: String) {
    messageList.add(ChatItem(message, true))
    // messages.value = messageList
    messages.value = messageList.toMutableList() // Copy it to a new memory address
}

This issue might arise if you get the same ComposeView attached twice to a Window, or reuse it (e.g. calling setContentView twice with a view hierarchy instance that contains a ComposeView).

There's an open issue for that: https://issuetracker.google.com/issues/197773820

Related