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

Compose升级致BottomSheetScaffold触发IndexOutOfBoundsException崩溃

检索过该问题的相关公开解决方案但未找到有效内容,自行排查定位并修复问题后,将问题场景、复现方式、相关日志、根因及修复方案整理如下,供遇到同类问题的开发者参考。

问题描述

将Jetpack Compose从1.2.0-beta02版本升级至1.2.0-rc02版本后,页面出现无业务代码改动的崩溃。经逐一定位排查,确认问题根源为BottomSheetScaffold组件:当组件的content区域没有直接布局的子组件(仅放置弹窗类单独渲染的组件)时,就会触发崩溃。

触发崩溃的示例代码

BottomSheetScaffold(
    sheetContent = { Text(text = "Some sheet content") }
) {
    AlertDialog(
        onDismissRequest = {
            // no-op
        },
        buttons = {
            Text(text = "here goes a button")
        }
    )
}

崩溃日志

2022-07-01 10:02:07.185 16257-16257/my.example.app E/AndroidRuntime: FATAL EXCEPTION: main
    Process: my.example.app, PID: 16257
    java.lang.IndexOutOfBoundsException: Index 0 is out of bounds. The list has 0 elements.
        at androidx.compose.runtime.collection.MutableVectorKt.checkIndex(MutableVector.kt:1135)
        at androidx.compose.runtime.collection.MutableVectorKt.access$checkIndex(MutableVector.kt:1)
        at androidx.compose.runtime.collection.MutableVector$MutableVectorList.get(MutableVector.kt:940)
        at androidx.compose.material.BottomSheetScaffoldKt$BottomSheetScaffoldLayout$1$1.invoke-0kLqBqw(BottomSheetScaffold.kt:447)
        at androidx.compose.material.BottomSheetScaffoldKt$BottomSheetScaffoldLayout$1$1.invoke(BottomSheetScaffold.kt:430)
        at androidx.compose.ui.layout.LayoutNodeSubcompositionsState$createMeasurePolicy$1.measure-3p2s80s(SubcomposeLayout.kt:590)
        at androidx.compose.ui.node.InnerPlaceable.measure-BRTryo0(InnerPlaceable.kt:44)
        at androidx.compose.ui.node.LayoutNode$performMeasure$1.invoke(LayoutNode.kt:1428)
        at androidx.compose.ui.node.LayoutNode$performMeasure$1.invoke(LayoutNode.kt:1427)
        at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:2101)
        at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:110)
        at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui_release(OwnerSnapshotObserver.kt:78)
        at androidx.compose.ui.node.OwnerSnapshotObserver.observeMeasureSnapshotReads$ui_release(OwnerSnapshotObserver.kt:66)
        at androidx.compose.ui.node.LayoutNode.performMeasure-BRTryo0$ui_release(LayoutNode.kt:1427)
        at androidx.compose.ui.node.OuterMeasurablePlaceable.remeasure-BRTryo0(OuterMeasurablePlaceable.kt:94)
        at androidx.compose.ui.node.OuterMeasurablePlaceable.measure-BRTryo0(OuterMeasurablePlaceable.kt:75)
        at androidx.compose.ui.node.LayoutNode.measure-BRTryo0(LayoutNode.kt:1366)
        at androidx.compose.foundation.layout.BoxKt$boxMeasurePolicy$1.measure-3p2s80s(Box.kt:115)
        at androidx.compose.ui.node.InnerPlaceable.measure-BRTryo0(InnerPlaceable.kt:44)
        at androidx.compose.ui.graphics.SimpleGraphicsLayerModifier.measure-3p2s80s(GraphicsLayerModifier.kt:405)
        at androidx.compose.ui.node.ModifiedLayoutNode.measure-BRTryo0(ModifiedLayoutNode.kt:53)
        at androidx.compose.foundation.layout.FillModifier.measure-3p2s80s(Size.kt:658)
        at androidx.compose.ui.node.ModifiedLayoutNode.measure-BRTryo0(ModifiedLayoutNode.kt:53)
        at androidx.compose.ui.node.LayoutNode$performMeasure$1.invoke(LayoutNode.kt:1428)
        at androidx.compose.ui.node.LayoutNode$performMeasure$1.invoke(LayoutNode.kt:1427)
        at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:2101)
        at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:110)
        at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui_release(OwnerSnapshotObserver.kt:78)
        at androidx.compose.ui.node.OwnerSnapshotObserver.observeMeasureSnapshotReads$ui_release(OwnerSnapshotObserver.kt:66)
        at androidx.compose.ui.node.LayoutNode.performMeasure-BRTryo0$ui_release(LayoutNode.kt:1427)
        at androidx.compose.ui.node.OuterMeasurablePlaceable.remeasure-BRTryo0(OuterMeasurablePlaceable.kt:94)
        at androidx.compose.ui.node.OuterMeasurablePlaceable.measure-BRTryo0(OuterMeasurablePlaceable.kt:75)
        at androidx.compose.ui.node.LayoutNode.measure-BRTryo0(LayoutNode.kt:1366)
        at androidx.compose.foundation.layout.BoxKt$boxMeasurePolicy$1.measure-3p2s80s(Box.kt:115)
        at androidx.compose.ui.node.InnerPlaceable.measure-BRTryo0(InnerPlaceable.kt:44)
        at androidx.compose.ui.graphics.BlockGraphicsLayerModifier.measure-3p2s80s(GraphicsLayerModifier.kt:342)
        at androidx.compose.ui.node.ModifiedLayoutNode.measure-BRTryo0(ModifiedLayoutNode.kt:53)
        at androidx.compose.ui.node.LayoutNode$performMeasure$1.invoke(LayoutNode.kt:1428)
        at androidx.compose.ui.node.LayoutNode$performMeasure$1.invoke(LayoutNode.kt:1427)
        at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:2101)
根因分析

1.2.0-rc02版本的BottomSheetScaffold在布局测量阶段,会直接读取content子项列表的第0个元素做尺寸计算,没有做空判断。AlertDialog这类弹窗组件不会被添加到当前BottomSheetScaffold的子项列表中,会单独渲染到独立窗口,最终导致子项列表为空时触发索引越界崩溃。

修复方案

在BottomSheetScaffold的content作用域下,先放置一个基础布局组件(如Box)作为根容器,哪怕容器内容为空也可,再将弹窗等其他组件放在该容器内部即可。
修复后的代码示例:

BottomSheetScaffold(
    sheetContent = { Text(text = "Some sheet content") }
) {
    // 先添加基础布局容器作为content的直接子项
    Box(modifier = Modifier.fillMaxSize()) {
        AlertDialog(
            onDismissRequest = {
                // 业务逻辑
            },
            buttons = {
                Text(text = "here goes a button")
            }
        )
    }
}

内容的提问来源于stack exchange,提问作者mr. Gauss

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 00:45:44