SavedStateHandle ViewModel 未在导航和堆栈清除中保留状态

问题描述 投票:0回答:1

我有一个由 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
    }
}
android kotlin android-jetpack-compose android-viewmodel jetpack-compose-navigation
1个回答
0
投票

查看表格。当用户在屏幕之间导航时,

SavedStateHandle
不会保留。如果应用程序崩溃或方向更改,它可以返回值,但当用户按下后退按钮时则不会返回值。

如果您的逻辑需要永久保存状态,请使用持久存储,例如DataStore。如果逻辑需要仅为当前会话保存值,您可以在片段或片段与父活动之间使用

SharedViewModel
guide)。或者当使用 args 导航到目的地时,使用导航组件在两个方向上传输数据。

© www.soinside.com 2019 - 2024. All rights reserved.