5

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
  }
}
Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
Berkay Kireçci
  • 651
  • 5
  • 18

2 Answers2

4

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
}
Wilson Tran
  • 4,050
  • 3
  • 22
  • 31
  • I just tried your solution but it didn't help. Thanks for your help. – Berkay Kireçci Feb 28 '21 at 11:03
  • Another solution, use by mutableStateOf(...) follow by https://developer.android.com/codelabs/jetpack-compose-state?continue=https%3A%2F%2Fdeveloper.android.com%2Fcourses%2Fpathways%2Fcompose%23codelab-https%3A%2F%2Fdeveloper.android.com%2Fcodelabs%2Fjetpack-compose-state#8 – Wilson Tran Feb 28 '21 at 11:11
  • I changed my livedata to state as in codelab explained. I also passed my list in composable constructer. Nothing has changed. I wonder what i am missing.. – Berkay Kireçci Feb 28 '21 at 11:59
  • @BerkayKireçci did you find a solution? – user3124306 Mar 14 '21 at 17:36
0

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

Louis CAD
  • 10,965
  • 2
  • 39
  • 58