Jetpack Compose点击LazyColumn行项显示底部弹窗崩溃问题排查
崩溃原因排查与解决方案
核心崩溃原因
全局变量非法赋值导致状态混乱
你把sheetState和sheetScope作为全局变量在ShowBottomSheetDialog中赋值,而Composable的状态必须通过remember在局部持有。全局变量会在每次重组时被覆盖,引发BottomSheet状态不一致,最终导致崩溃。强制非空断言触发空指针异常
sheetUser!!的使用没有确保sheetUser一定非空,在状态更新的间隙(比如showSheet先变为true,sheetUser还没完成赋值)或配置变更时,sheetUser可能为null,直接触发NPE。Composition阶段启动协程违反生命周期
在if(showSheet)代码块中直接调用sheetScope.launch,会在每次Composable重组时重复执行,多次触发sheetState.show(),导致BottomSheet内部状态异常。BottomSheet布局结构错误
ModalBottomSheetLayout应该作为根布局包裹所有需要显示BottomSheet的内容,而不是在条件判断中单独创建。原代码中ModalBottomSheetLayout的content为空,会破坏原有布局层级,引发渲染异常。
修复后的完整代码
修改后的SetRecyclerview函数
@OptIn(ExperimentalMaterialApi::class) @Composable fun SetRecyclerview(viewModel: UserViewModel, paddingValues: PaddingValues) { val isLoading = viewModel.isLoading.value var showSheet by remember { mutableStateOf(false) } var sheetUser: User? by remember { mutableStateOf(null) } val userList = viewModel.userData.collectAsState().value // 局部持有BottomSheet状态和协程作用域,避免全局变量问题 val sheetState = rememberModalBottomSheetState(initialValue = ModalBottomSheetValue.Hidden) val sheetScope = rememberCoroutineScope() // 用LaunchedEffect监听状态变化,仅在showSheet改变时执行协程操作 LaunchedEffect(showSheet) { if (showSheet) { sheetState.show() } else { sheetState.hide() } } // ModalBottomSheetLayout作为根布局,包裹所有内容 ModalBottomSheetLayout( sheetState = sheetState, sheetContent = { // 安全访问sheetUser,避免空指针 sheetUser?.let { BottomSheetItem(user = it) } }, sheetBackgroundColor = Color.White, sheetShape = RoundedCornerShape(topStart = 20.dp, topEnd = 20.dp), ) { if (isLoading) { ProgressBarComponent() } else { LazyColumn( modifier = Modifier.padding(0.dp, 5.dp, 0.dp, 5.dp) ) { userList.forEach { user -> items(user.results.size) { index -> val currentUser = user.results[index] EachRow(user = currentUser, onClick = { sheetUser = currentUser showSheet = true }) } } } } } }
保留原BottomSheetItem函数
//Bottom Sheet Item @Composable fun BottomSheetItem(user: User) { Log.e("TAG", "BottomSheetItem: " + user.email) }
关键修改说明
- 用
remember在SetRecyclerview局部持有sheetState和sheetScope,确保状态与当前Composable节点绑定,避免全局状态冲突。 - 使用
LaunchedEffect监听showSheet的变化,仅在状态变更时执行协程操作,符合Compose生命周期规则,避免重复触发。 ModalBottomSheetLayout作为根布局包裹所有内容,保证BottomSheet显示时不会破坏原有布局结构。- 用
sheetUser?.let替代强制非空断言,安全访问用户数据,避免空指针异常。 - 移除了危险的
@SuppressLint("CoroutineCreationDuringComposition")注解,代码符合Compose最佳实践。
内容的提问来源于stack exchange,提问作者Saad
相关产品推荐
相关产品推荐

