https://kotlinlang.org logo
Title
i

ildar.i [Android]

05/03/2022, 7:05 AM
Hello, we have a state object
CommonInput
in viewModel, which gets posted to StateFlow and then converted into a
@Composable fun CommonInputDisplay
in our Composable screen.
CommonInput
has a
value
param that gets converted to
MutableState
and used in
TextField
as
value
. The problem is that once it has initialized, we can’t change
TextField
value
by modifying state object from ViewModel anymore. How can we initiate a recomposition with a new value from viewModel by modifying
CommonInput
?
f

Filip Wiesner

05/03/2022, 7:15 AM
CommonInput::value
could be a Compose
State
🤷
Something like
class CommonInput(
  val initialValue: String? = null
  ...
) {
  var value by mutableStateOf(initialalue)
    private set
}
i

ildar.i [Android]

05/03/2022, 7:17 AM
I know, but can ViewModel be not aware of compose? Ideally it should just post new state and Compose screen just updates
1
y

yschimke

05/03/2022, 7:17 AM
You could pass it in as a State<X> or lambda. But that feels wrong. Why not make it a val and pass in a new CommonInput instance. If you want to avoid work on recomposition, you could remember other things on the stable fields.
f

Filip Wiesner

05/03/2022, 7:18 AM
Ideally it should just post new state and Compose screen just updates
Sure but in that case the
CommonInput
cannot have mutable properties and cannot mutate iteslf. ViewModel has to do that like yschmke suggests:
make it a val and pass in a new CommonInput instance
y

yschimke

05/03/2022, 7:19 AM
Exactly. I think you are fighting compose by using mutable fields.
👆 1
i

ildar.i [Android]

05/03/2022, 7:34 AM
Right now even if I change all vars to val my screen doesn’t recompose after I post updated state to StateFlow. The values on ViewModel are new, but UI stays the same
f

Filip Wiesner

05/03/2022, 7:35 AM
Try changing the
CommonInput
class
to
data class
i

ildar.i [Android]

05/03/2022, 7:38 AM
No change as well with
data class
f

Filip Wiesner

05/03/2022, 7:41 AM
Can you show us how do you emit new values to your state flow and how do you collect it?
i

ildar.i [Android]

05/03/2022, 7:54 AM
LaunchedEffect(item.value) {
    if (item.value.orEmpty() != inputText) inputText = item.value.orEmpty()
}
I added this after
inputText
initialization and it started to work properly. Is that a correct thing to do here?
f

Filip Wiesner

05/03/2022, 8:08 AM
The
inpuText
should just be
val inputText = item.value.orEmpty()
. No need to create internal state
i

ildar.i [Android]

05/03/2022, 8:09 AM
yeah, indeed) thank you!
🎉 1
f

Filip Wiesner

05/03/2022, 8:09 AM
And your
onValueChange
should just call the VM to emit new state - single source of truth
👌 1