Lukasz Kalnik
02/16/2022, 4:56 PMLukasz Kalnik
02/16/2022, 4:56 PM@Composable
fun EnterNameDialog(
uiState: EnterNameDialogState
) {
val currentText = remember { mutableStateOf(uiState.name) }
AlertDialog(
// ....
text = {
TextField(
value = currentText.value
onValueChange = { currentText.value = it }
// ...
}
data class EnterNameDialogState(
val show: Boolean,
val name: String,
)Lukasz Kalnik
02/16/2022, 5:00 PM"test" inside of uiState.name, when setting a breakpoint it gets immediately set to empty string in currentText.value. It is also empty in the UI obviously.Lukasz Kalnik
02/16/2022, 5:01 PM"" when the user dismisses/confirms the dialog. Is it possible that the remember remembers this old state from previous composition?Adam Powell
02/16/2022, 5:06 PMcurrentText.value is set to ""?Adam Powell
02/16/2022, 5:07 PMuiState.name directly and report new values up either via callback or method on uiState so that they can be applied to uiStateLukasz Kalnik
02/16/2022, 5:13 PMonValueChange was directly calling up to ViewModel callback which was only in charge of the name etc.).
However we have changed that after adding a trailing icon to clear the text.
It was convenient to keep the editing of the text internally via remember and only send the text up to ViewModel when the user confirmed the dialog.Lukasz Kalnik
02/16/2022, 5:14 PMAdam Powell
02/16/2022, 5:17 PMLukasz Kalnik
02/16/2022, 5:17 PMcurrentText = remember // ...?Adam Powell
02/16/2022, 5:17 PMEnterNameDialog is calledLukasz Kalnik
02/16/2022, 5:49 PMval currentText = remember { } line and added the callback to viewModel for onValueChange and everything works perfectly.Lukasz Kalnik
02/16/2022, 5:49 PMremember.Lukasz Kalnik
02/17/2022, 10:11 AMcurrentText.value was always reset to "".remember { mutableStateOf(value) } works. I thought you can kind of reinitialize it from outside, by passing a new value.remember makes the computation inside lazy, and only calls it the first time, initializing it with value.value as "" indeed at the first call site of EnterNameDialog, when user entered the screen. So we couldn't change it later because of remember.Lukasz Kalnik
02/17/2022, 4:39 PMremember.
You just need to use remember with an additional parameter as key. This way the remembered value will get recalculated every time the key changes:
val currentText = remember(uiState.name) { mutableStateOf(uiState.name) }
That updates currentText every time uiState.name changes.Lukasz Kalnik
02/18/2022, 10:53 AMremember to uiState.name, it will only recalculate its value if it receives a new uiState.name but with a different value than the previous uiState.name it was initialized with.
So the approach from the message above doesn't work in the following scenario:
1. App shows the dialog, initializing it with an empty string as uiState.name
2. User types something like "test"
3. User clicks the "OK" button
4. Dialog is dismissed
5. User opens the dialog again
6. App code again initializes the dialog with an empty string as uiState.name
7. remember looks at uiState.name and compares it with its previous value
8. Both values are empty strings, so remember determines the key didn't change
9. Because of that, remember decides there's no need to reinitialize currentText so it provides the cached value
10. But the cached currentText value was last updated by the user typing "test" the previous time the dialog was opened
11. So dialog now opens with the old "test" text instead of the empty string from uiState.nameLukasz Kalnik
02/18/2022, 10:59 AMkey for remember reinitialization something that is guaranteed to change every time you want to reinitialize currentText.
In my case EnterNameDialogState contains a show variable, which defines if the dialog is shown or hidden.
So if I want to reinitialize the remembered currentText every time the dialog is shown or hidden, I just couple the remember invocation to uiState.show (instead of uiState.name as before). Note that inside of mutableStateOf() we still have uiState.name, because that's what we want to reinitialize currentText with:
val currentText = remember(uiState.show) { mutableStateOf(uiState.name) }
What it does is "whenever uiState.show is changed, reinitialize currentText with a MutableState of uiState.name, otherwise provide cached value".