展开状态的ExposedDropdownMenu导航至其他Fragment时致应用崩溃
这个崩溃的核心原因是:导航操作触发Fragment/Compose销毁时,ExposedDropdownMenu的PopupLayout还没来得及从WindowManager中移除,后续它尝试更新布局时找不到关联的Window,就抛出了异常。你已经尝试在导航前收起菜单,但Compose的状态更新是异步的,导航操作同步执行导致时机不匹配。
以下是几个可行的解决办法:
1. 等待菜单收起状态生效后再导航
利用LaunchedEffect监听菜单展开状态,仅当状态确实变为收起后再执行导航操作,确保Compose完成重组、Popup已被移除:
// ViewModel中托管状态 class YourViewModel : ViewModel() { val isDropdownExpanded = mutableStateOf(false) // 其他状态... } // Composable代码 @Composable fun YourScreen(viewModel: YourViewModel, navController: NavController) { val isExpanded by viewModel.isDropdownExpanded // 监听菜单收起事件,执行导航 LaunchedEffect(isExpanded) { if (!isExpanded) { // 这里执行导航 navController.navigate("target_screen") } } Button( onClick = { // 先收起菜单,触发状态更新 viewModel.isDropdownExpanded.value = false } ) { Text("跳转") } // 你的ExposedDropdownMenu代码 ExposedDropdownMenu( expanded = isExpanded, onDismissRequest = { viewModel.isDropdownExpanded.value = false } ) { // 菜单选项... } }
2. 禁用导航按钮直到菜单完全收起
在菜单展开时,将导航按钮设为不可点击,从源头避免用户在菜单未收起时触发导航:
Button( onClick = { navController.navigate("target_screen") }, enabled = !isExpanded // 菜单展开时禁用按钮 ) { Text("跳转") }
3. 在Compose销毁前强制清理菜单
利用DisposableEffect,在Composable即将离开组合时,强制收起菜单,确保Popup被正确移除:
@Composable fun YourScreen(viewModel: YourViewModel, navController: NavController) { val isExpanded by viewModel.isDropdownExpanded // 当Compose离开组合时,强制收起菜单 DisposableEffect(Unit) { onDispose { viewModel.isDropdownExpanded.value = false } } // 其余代码... }
4. 应急方案:延迟导航(不推荐)
如果以上方案暂时无法适配,可以给菜单收起留一点缓冲时间再导航,但这种方式依赖设备性能,不是最优解:
Button( onClick = { viewModel.isDropdownExpanded.value = false // 延迟200ms再导航,给Popup足够的销毁时间 CoroutineScope(Dispatchers.Main).launch { delay(200) navController.navigate("target_screen") } } ) { Text("跳转") }
内容的提问来源于stack exchange,提问作者Ygor
相关产品推荐
相关产品推荐

