我有一个由 Jetpack Navigation 管理的具有多个屏幕的 Android 应用程序。在我的应用程序中,我在 ViewModel 中使用
SavedStateHandle
来保留配置更改和导航事件中的某些状态。具体来说,我有一个场景,从 ScreenFirst
导航到 ScreenSecond
,然后在 ScreenSecond
上,我根据 isBackButtonVisible
的值切换按钮的可见性。
但是,尽管将此值保存在
SavedStateHandle
中,当我按“后退”按钮返回到 ScreenFirst
,然后导航回 ScreenSecond
时,按钮的可见性始终重置为其初始状态(false),而不是保留之前设置的值。
此外,我想在从一个屏幕导航到另一个屏幕时清除返回堆栈,以确保一致的导航流程。虽然我已经实现了
popUpTo
来清除返回堆栈,但它似乎并不影响isBackButtonVisible
值的保存。
如何确保 ViewModel 中的
SavedStateHandle
保留导航事件和返回堆栈清除的状态?是什么原因导致状态未正确保留的问题?
import 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
}
}