ModalBottomSheet在Release版本(API23)崩溃,求解决方案
API23 Release版本下ModalBottomSheet崩溃问题及临时解决方案
问题现象
Debug版本运行正常,但在**API23(Marshmallow)**的Release版本(即使关闭代码混淆)中,使用ModalBottomSheet会触发如下崩溃:
java.lang.IllegalStateException: The offset was read before being initialized. Did you access the offset in a phase before layout, like effects or composition? at androidx.compose.material3.AnchoredDraggableState.requireOffset(AnchoredDraggable.kt:344) at androidx.compose.material3.SheetState.requireOffset(SheetDefaults.kt:164) at androidx.compose.material3.ModalBottomSheet_androidKt$ModalBottomSheet$3$1$2$1.invoke-Bjo55l4(ModalBottomSheet.android.kt:202) at androidx.compose.material3.ModalBottomSheet_androidKt$ModalBottomSheet$3$1$2$1.invoke(ModalBottomSheet.android.kt:198) at androidx.compose.foundation.layout.OffsetPxNode$measure$1.invoke(Offset.kt:247) at androidx.compose.foundation.layout.OffsetPxNode$measure$1.invoke(Offset.kt:246) at androidx.compose.ui.node.LookaheadCapablePlaceable$layout$1.placeChildren(LookaheadDelegate.kt:107) at androidx.compose.ui.node.LayoutModifierNodeCoordinator.placeAt-f8xVGno(LayoutModifierNodeCoordinator.kt:167) at androidx.compose.ui.layout.Placeable.access$placeAt-f8xVGno(Placeable.kt:33) at androidx.compose.ui.layout.Placeable$PlacementScope.placeRelative(Placeable.kt:417) at androidx.compose.ui.layout.Placeable$PlacementScope.placeRelative$default(Placeable.kt:203) at androidx.compose.foundation.layout.FillNode$measure$1.invoke(Size.kt:704) at androidx.compose.foundation.layout.FillNode$measure$1.invoke(Size.kt:703) at androidx.compose.ui.node.LookaheadCapablePlaceable$layout$1.placeChildren(LookaheadDelegate.kt:107) at androidx.compose.ui.node.LayoutModifierNodeCoordinator.placeAt-f8xVGno(LayoutModifierNodeCoordinator.kt:167) at androidx.compose.ui.layout.Placeable.access$placeAt-f8xVGno(Placeable.kt:33) at androidx.compose.ui.layout.Placeable$PlacementScope.placeRelative(Placeable.kt:417) at androidx.compose.ui.layout.Placeable$PlacementScope.placeRelative$default(Placeable.kt:203) at androidx.compose.foundation.layout.SizeNode$measure$1.invoke(Size.kt:840) at androidx.compose.foundation.layout.SizeNode$measure$1.invoke(Size.kt:839) at androidx.compose.ui.node.LookaheadCapablePlaceable$layout$1.placeChildren(LookaheadDelegate.kt:107) at androidx.compose.ui.node.LayoutModifierNodeCoordinator.placeAt-f8xVGno(LayoutModifierNodeCoordinator.kt:167) at androidx.compose.ui.layout.Placeable.access$placeAt-f8xVGno(Placeable.kt:33) at androidx.compose.ui.layout.Placeable$PlacementScope.place-70tqf50(Placeable.kt:428) at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate$placeOuterCoordinatorBlock$1.invoke(LayoutNodeLayoutDelegate.kt:489) at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate$placeOuterCoordinatorBlock$1.invoke(LayoutNodeLayoutDelegate.kt:483) at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:2303) at androidx.compose.runtime.snapshots.SnapshotStateObserver$ObservedScopeMap.observe(SnapshotStateObserver.kt:500) at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:256) at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui_release(OwnerSnapshotObserver.kt:133) at androidx.compose.ui.node.OwnerSnapshotObserver.observeLayoutModifierSnapshotReads$ui_release(OwnerSnapshotObserver.kt:98) at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.placeOuterCoordinator-f8xVGno(LayoutNodeLayoutDelegate.kt:753) at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.placeAt-f8xVGno(LayoutNodeLayoutDelegate.kt:724) at androidx.compose.ui.layout.Placeable.access$placeAt-f8xVGno(Placeable.kt:33) at androidx.compose.ui.layout.Placeable$PlacementScope.place-70tqf50(Placeable.kt:428) at androidx.compose.ui.layout.Placeable$PlacementScope.place-70tqf50$default(Placeable.kt:230) at androidx.compose.foundation.layout.BoxKt.placeInBox(Box.kt:194) at androidx.compose.foundation.layout.BoxKt.access$placeInBox(Box.kt:1) at androidx.compose.foundation.layout.BoxMeasurePolicy$measure$5.invoke(Box.kt:174)
复现步骤
使用androidx.compose:compose-bom:2024.06.00创建新Compose项目,替换MainActivity代码为以下内容即可触发崩溃:
package com.example.myapplication import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ModalBottomSheet import androidx.compose.material3.Text import androidx.compose.ui.Modifier import com.example.myapplication.ui.theme.MyApplicationTheme class MainActivity : ComponentActivity() { @OptIn(ExperimentalMaterial3Api::class) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() setContent { MyApplicationTheme { ModalBottomSheet( onDismissRequest = { } ) { Column(Modifier.fillMaxWidth()) { Text(text = "Hello Dear!") Text(text = "Hello Dear!") Text(text = "Hello Dear!") Text(text = "Hello Dear!") } } } } } }
临时解决方案
已知该问题已上报至谷歌并标记修复,但当前版本仍存在,可尝试以下临时方案:
方案1:延迟初始化SheetState
手动创建SheetState并在布局完成后再初始化状态,避免在布局前读取未初始化的offset:@OptIn(ExperimentalMaterial3Api::class) val sheetState = rememberSheetState(skipPartiallyExpanded = true) LaunchedEffect(Unit) { // 延迟触发状态变更,确保布局完成 sheetState.animateTo(SheetValue.Expanded) }随后将
ModalBottomSheet的sheetState参数设置为该对象。方案2:禁用Lookahead布局
针对API23设备,全局或局部禁用Lookahead布局,避免布局阶段提前读取状态:
在Activity的onCreate中添加:if (Build.VERSION.SDK_INT == Build.VERSION_CODES.M) { // 禁用Lookahead布局 CompositionLocalProvider(LocalLookaheadLayoutScope provides null) { // 你的Compose内容 } }方案3:降级Compose依赖版本
暂时回退到compose-bom:2024.04.00或更早版本,该问题在旧版本中未出现。
内容的提问来源于stack exchange,提问作者user4617571
相关产品推荐
相关产品推荐

