You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 22:17:45