I wanna use a state holder class to keep some app level state things, for example, if a dialog must be displayed. For that, I added title and message variables in the app state holder class. When I set them to a value different from null, that should display a dialog on my app, because I'm checking if these variables are different from null for displaying it on my screen composable. Something is not working because when I set these variables to a value different from null nothing happens. It seems that recomposition is not being started.
This is the app state composable and the remember function I use to remember it:
val appStateHolder = rememberAppStateHolder()
@Composable
fun rememberAppStateHolder(
navController: NavHostController = rememberNavController(),
dialogTitle: StringResource? = null,
dialogMessage: StringResource? = null,
): AppStateHolder {
return remember(
navController,
dialogTitle,
dialogMessage
) {
AppStateHolder(
navController = navController,
dialogTitle = dialogTitle,
dialogMessage = dialogMessage
)
}
}
More:
@Stable
class AppStateHolder(
val navController: NavHostController = NavHostController(),
var dialogTitle: StringResource? = null,
var dialogMessage: StringResource? = null
) {
// UI State
val currentDestination: NavDestination?
@Composable get() = navController
.currentBackStackEntryAsState().value?.destination
fun isDialogEnabled(): Boolean {
return (dialogTitle != null || dialogMessage != null)
}
// UI logic
fun navigate(route: String) {
navController.navigate(route)
}
fun showDialog(dialogTitle: StringResource, dialogMessage: StringResource) {
this.dialogTitle = dialogTitle
this.dialogMessage = dialogMessage
}
fun hideDialog() {
this.dialogTitle = null
this.dialogMessage = null
}
}
This is how I check if the dialog should be displayed:
if (appStateHolder.isDialogEnabled()) {
MessageDialog(
title = stringResource(Res.string.about),
message = stringResource(Res.string.about_message),
onCloseRequest = { appStateHolder.hideDialog() }
)
}
This is how I set the dialog values to different of null:
appStateHolder.showDialog(title, message)
As long as the keys passed into remember
has not changed the enclosing block cannot be re-evaluated. In other words the initial instance of your AppStateHolder
class is what you still have in the composition.
So every time you do this:
appStateHolder.showDialog(title, message)
The changes are not reflected in the composition because it doesn't know of any mutating object.
To fix that, you can make dialogTitle
and dialogMessage
be a MutableState
.
class AppStateHolder(
val navController: NavHostController = NavHostController()
){
var dialogTitle: String? by mutableStateOf(null)
var dialogMessage: String? by mutableStateOf(null)
}
Then mutate the values like you did before. That should work.