Jetpack Compose中ModalBottomSheet程序化关闭致内存泄漏问题
问题分析与修复方案
你的问题核心在于错误地使用SheetState.isVisible来控制ModalBottomSheet的显示/隐藏,这会导致组件在关闭动画未完成时被强制移除,引发资源未正确释放的内存泄漏和频繁GC。
错误原因
ModalBottomSheet需要由开发者维护的独立状态变量控制可见性,而非依赖SheetState.isVisible。当调用bottomSheetState.hide()后,底部弹窗会执行关闭动画,isVisible会在动画结束后才变为false;但你的代码会在isVisible变为false时立即移除BottomSheetContent,导致ModalBottomSheet的内部协程、动画资源等无法正常回收,进而引发内存泄漏和持续GC日志。
修复代码
1. 主界面(TestScreen)修改
使用独立状态变量控制弹窗可见性,并同步弹窗状态:
@OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class) @Composable fun TestScreen( modifier: Modifier = Modifier, ) { val coroutineScope = rememberCoroutineScope() val bottomSheetState = rememberModalBottomSheetState( skipPartiallyExpanded = false ) // 独立状态变量控制弹窗显示 var showBottomSheet by remember { mutableStateOf(false) } // 弹窗隐藏完成后更新状态变量 LaunchedEffect(bottomSheetState.isVisible) { if (!bottomSheetState.isVisible) { showBottomSheet = false } } // 仅当showBottomSheet为true时渲染弹窗 if (showBottomSheet) { BottomSheetContent( bottomSheetState = bottomSheetState, onDismiss = { showBottomSheet = false }, modifier = modifier ) } Column( horizontalAlignment = Alignment.CenterHorizontally, modifier = Modifier.fillMaxSize(), verticalArrangement = Arrangement.Center ) { Button( onClick = { showBottomSheet = true // 弹窗显示后触发展开动画 coroutineScope.launch { bottomSheetState.expand() } } ) { Text("Open bottom sheet") } } }
2. 弹窗内容(BottomSheetContent)修改
通过回调通知主界面更新状态,确保关闭流程完整:
@Composable @OptIn(ExperimentalMaterial3Api::class) fun BottomSheetContent( modifier: Modifier, bottomSheetState: SheetState, onDismiss: () -> Unit, ) { val coroutineScope = rememberCoroutineScope() ModalBottomSheet( onDismissRequest = { coroutineScope.launch { bottomSheetState.hide() // 隐藏完成后触发回调 onDismiss() } }, sheetState = bottomSheetState, modifier = modifier ) { Button( onClick = { coroutineScope.launch { bottomSheetState.hide() onDismiss() } } ) { Text("Close bottom sheet") } } }
额外说明
- 始终使用独立的状态变量控制
ModalBottomSheet的可见性,避免依赖SheetState的状态直接做条件渲染。 - 关闭弹窗时,先调用
bottomSheetState.hide()完成动画,再更新状态变量移除组件,确保内部资源有足够时间回收。 - 若仍有内存泄漏,可检查是否存在其他持有
SheetState或弹窗组件引用的对象(如全局协程、静态变量)未被正确释放。
内容的提问来源于stack exchange,提问作者StackerSapper
相关产品推荐
相关产品推荐

