KotlinLeaner
03/14/2024, 12:24 PMSavedStateHandle
in my ViewModel to preserve certain states across configuration changes and navigation events. Specifically, I have a scenario where I navigate from ScreenFirst
to ScreenSecond
, and on ScreenSecond
, I toggle the visibility of a button based on the value of isBackButtonVisible
.
However, despite saving this value in the SavedStateHandle
, when I press the Back button to return to ScreenFirst
and then navigate back to ScreenSecond
, the visibility of the button is always reset to its initial state (false), instead of retaining the previously set value.
Additionally, I want to clear the back stack when navigating from one screen to another to ensure a consistent navigation flow. Although I've implemented popUpTo
to clear the back stack, it doesn't seem to affect the preservation of the isBackButtonVisible
value.
How can I ensure that the SavedStateHandle
in my ViewModel preserves the state across navigation events and back stack clearing? What could be causing the issue with the state not being retained properly?KotlinLeaner
03/14/2024, 12:24 PMimport android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material.Button
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.Modifier
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewmodel.compose.SavedStateHandleSaveableApi
import androidx.lifecycle.viewmodel.compose.saveable
import androidx.navigation.NavController
import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import org.koin.androidx.compose.navigation.koinNavViewModel
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
NavigationScreen()
}
}
}
@Composable
fun NavigationScreen(navController: NavHostController = rememberNavController()) {
NavHost(
navController = navController,
startDestination = "ScreenFirst",
route = "parentRoute"
) {
composable("ScreenFirst") {
Button(onClick = {
navController.navigateWithClearStack("ScreenSecond")
}) {
Text(text = "Move to Second Screen")
}
}
composable("ScreenSecond") {
val viewModel: SecondViewModel = koinNavViewModel()
Column(modifier = Modifier.fillMaxSize()) {
Button(onClick = { viewModel.update(true) }) {
Text(text = "Show Back Button")
}
AnimatedVisibility(visible = viewModel.isBackButtonVisible) {
Button(onClick = {
navController.navigateWithClearStack("ScreenFirst")
}) {
Text(text = "Move to Back Screen")
}
}
}
}
}
}
fun NavController.navigateWithClearStack(screenRoute: String) {
this.navigate(screenRoute) {
// Clear the back stack up to the start destination
popUpTo(currentBackStackEntry?.destination?.route ?: return@navigate) {
inclusive = true
}
// Specify the new start destination
launchSingleTop = true
}
}
class SecondViewModel(savedStateHandle: SavedStateHandle) : ViewModel() {
@OptIn(SavedStateHandleSaveableApi::class)
var isBackButtonVisible by savedStateHandle.saveable { mutableStateOf(false) }
private set
fun update(value: Boolean) {
isBackButtonVisible = value
}
}
Stylianos Gakis
03/14/2024, 12:31 PM