Jetpack Compose二级页面导航栈异常问题求助
Deep Link代理页面导致二级页面导航栈异常修复
问题场景
为第三方OAuth回调实现了Deep Link代理页面,触发认证前保存当前页面路由,回调后读取路由导航回原页面。一级页面逻辑正常,但二级页面(如路由account/Settings)成功导航后,点击返回无法回到父页面(账户页),而是停留在当前二级页面。
问题根源
- 导航回目标页面时默认将页面添加到栈中,栈结构变为:账户页 → 代理页 → 设置页。返回时先回到代理页,代理页又重新导航到设置页,形成循环。
- 存储的路由值未及时清理,代理页每次进入都会读取旧路由重复导航。
LaunchedEffect(true)会在Composable重组时重复执行,触发多次导航。
修复方案
1. 导航时清理代理页栈
修改导航逻辑,用popUpTo移除栈中的代理页,避免返回循环:
// 在addProxy函数中修改goBack和goOnSuccess的实现 goBack = oldBackRoute?.let { backRoute -> { navController.navigate(backRoute) { // 从栈中移除代理页,inclusive=true表示同时移除当前代理页 popUpTo(LeafScreen.Account.Proxy.createRoute(root)) { inclusive = true } } } }, goOnSuccess = oldLoggedInRoute?.let { successRoute -> { navController.navigate(successRoute) { popUpTo(LeafScreen.Account.Proxy.createRoute(root)) { inclusive = true } // 确保目标页面只存在一个实例 launchSingleTop = true } } },
2. 读取存储路由后立即清理
读取backRoute和loggedInRoute后,立即清理存储,避免下次进入代理页重复使用旧值:
if (!oldBackRoute.isNullOrBlank()) { it.arguments!!.putString("backRoute", oldBackRoute) // 清理存储的路由值 clearValueFromStorage("backRoute") } if (!oldLoggedInRoute.isNullOrBlank()) { it.arguments!!.putString("loggedInRoute", oldLoggedInRoute) clearValueFromStorage("loggedInRoute") }
3. 确保LaunchedEffect仅执行一次
将LaunchedEffect的key改为code,避免重组时重复触发导航:
@Composable fun ProxyScreen( logViewModel: LogViewModel, deeplinkViewModel: DeeplinkViewModel, goBack: (() -> Unit)? = null, goOnSuccess: (() -> Unit)? = null, intentData: Bundle? ) { val code = intentData?.getString("code") LaunchedEffect(code) { delay(500) sharedIntentData = intentData if (!code.isNullOrBlank() && goOnSuccess != null) { goOnSuccess() } else { goBack?.invoke() } } // 原有UI代码不变 Column( modifier = Modifier.fillMaxSize(), verticalArrangement = Arrangement.Center, horizontalAlignment = Alignment.CenterHorizontally, ) { Box( modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center, ) { LoadingCircle() } } }
4. 避免修改Composable的arguments
直接使用读取到的oldBackRoute和oldLoggedInRoute构建导航回调,无需修改arguments,减少意外重组:
// 替换addProxy中的相关逻辑 val oldBackRoute = if (!code.isNullOrBlank()) loadValueFromStorage("backRoute") else null val oldLoggedInRoute = if (!code.isNullOrBlank()) loadValueFromStorage("loggedInRoute") else null ProxyScreen( logViewModel = logViewModel, deeplinkViewModel = deeplinkViewModel, goBack = oldBackRoute?.let { backRoute -> { navController.navigate(backRoute) { popUpTo(LeafScreen.Account.Proxy.createRoute(root)) { inclusive = true } } } }, goOnSuccess = oldLoggedInRoute?.let { successRoute -> { navController.navigate(successRoute) { popUpTo(LeafScreen.Account.Proxy.createRoute(root)) { inclusive = true } launchSingleTop = true } } }, intentData = it.arguments )
内容的提问来源于stack exchange,提问作者Bastian Noffer
相关产品推荐
相关产品推荐

