Android Compose Navigation对话框页面后台时自动出栈的解决方法
问题:应用最小化时Dialog类型导航页自动弹出栈
我的应用基于Jetpack Navigation实现页面导航,其中content/{mode}是一个Dialog类型的目的地。但当应用被最小化后,这个Dialog会自动从导航栈中被弹出,请问该如何阻止这种默认行为?
相关代码片段如下:
Surface(Modifier.fillMaxSize()) { NavHost(navController = navController, startDestination = if (AppSettings.authenticationEnabled) "welcome" else "home") { composable( route = "welcome", enterTransition = { fadeIn() }, exitTransition = { fadeOut() } ) { WelcomePage(navController) } composable( route = "home", enterTransition = { when (initialState.destination.route) { "welcome" -> fadeIn() "settings" -> slideInHorizontally { if (rtl) -it else it } else -> null } }, exitTransition = { when (targetState.destination.route) { "welcome" -> fadeOut() "settings" -> slideOutHorizontally { if (rtl) -it else it } else -> null } } ) { HomePage(navController, items/* todo */) } composable( route = "settings", enterTransition = { when (initialState.destination.route) { "welcome" -> fadeIn() "home" -> slideInHorizontally { if (rtl) it else -it } else -> null } }, exitTransition = { when (targetState.destination.route) { "welcome" -> fadeOut() "home" -> slideOutHorizontally { if (rtl) it else -it } else -> null } } ) { SettingsPage(navController) } dialog( // <--- 问题所在 route = "content/{mode}", dialogProperties = DialogProperties( dismissOnBackPress = false, dismissOnClickOutside = false, decorFitsSystemWindows = false, usePlatformDefaultWidth = false ) ) { ContentPage(navController) } } }
解决方案
这是Jetpack Navigation的默认行为:当应用进入后台时,所有Dialog类型的目的地都会被自动从导航栈中移除。可以通过以下两种方式解决:
方案一:使用Navigation原生配置修复
在Dialog目的地的配置中添加launchSingleTop = true和restoreState = true,利用Navigation的原生能力保留Dialog状态:
dialog( route = "content/{mode}", launchSingleTop = true, restoreState = true, dialogProperties = DialogProperties( dismissOnBackPress = false, dismissOnClickOutside = false, decorFitsSystemWindows = false, usePlatformDefaultWidth = false ) ) { ContentPage(navController) }
launchSingleTop:确保当导航到该Dialog时不会重复创建实例,避免栈中出现多个相同DialogrestoreState:当应用恢复前台时,自动恢复Dialog的状态和位置
方案二:手动监听生命周期并恢复Dialog
如果需要更精细的控制,可以通过监听应用生命周期,在后台时记录Dialog状态,前台恢复时重建Dialog:
- 记录后台前的Dialog状态
- 前台恢复时重新导航到该Dialog
示例代码:
class MainActivity : ComponentActivity() { private var needRestoreDialog = false private var dialogMode: String? = null private lateinit var navController: NavController override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // 初始化NavController等代码... lifecycle.addObserver(object : DefaultLifecycleObserver { override fun onPause(owner: LifecycleOwner) { super.onPause(owner) // 检查当前栈顶是否是目标Dialog val currentRoute = navController.currentDestination?.route if (currentRoute?.startsWith("content/") == true) { needRestoreDialog = true // 提取Dialog的mode参数 dialogMode = navController.currentBackStackEntry?.arguments?.getString("mode") } else { needRestoreDialog = false } } override fun onResume(owner: LifecycleOwner) { super.onResume(owner) // 恢复Dialog if (needRestoreDialog && dialogMode != null) { navController.navigate("content/$dialogMode") needRestoreDialog = false } } }) } }
说明
方案一是更简洁的原生解决方案,推荐优先使用;方案二适合需要自定义逻辑的场景,比如需要额外处理Dialog的状态数据。
内容的提问来源于stack exchange,提问作者Mohammad Mostafa Dastjerdi
相关产品推荐
相关产品推荐

