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

Jetpack Compose对话框闪显即消失问题求助

问题:Jetpack Compose权限处理模块对话框闪显消失

基于Jetpack Compose开发的权限处理模块,代码逻辑无报错,但对话框仅闪显约1毫秒就消失,需持续点击对话框按钮才能查看。尝试更换不同AlertDialog组件后问题仍存在,最初怀疑是依赖库版本或Gradle配置导致,实际是代码逻辑存在多处问题。

相关代码
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
@OptIn(ExperimentalPermissionsApi::class)
@Composable
fun PermissionHandling(context: Context) {

    val permissionState = rememberMultiplePermissionsState(
        permissions = listOf(Manifest.permission.CAMERA, Manifest.permission.READ_MEDIA_IMAGES)
    )

    val lifecycleOwner = LocalLifecycleOwner.current
    var showDialog by remember { mutableStateOf(true) }


    DisposableEffect(key1 = lifecycleOwner, effect = {
        val observer = LifecycleEventObserver { _, event ->
            if (event == Lifecycle.Event.ON_START) {

                /** Figure out why is permission status not shown when permissions are first set **/

                val job = lifecycleScope.launch(Dispatchers.Default) {
                    permissionState.launchMultiplePermissionRequest()
                    delay(1000L)
                }

                runBlocking {
                    delay(2000L)
                    job.join()
                }
            }
        }
        lifecycleOwner.lifecycle.addObserver(observer)
        onDispose {
            lifecycleOwner.lifecycle.removeObserver(observer)
        }
    })

    permissionState.permissions.forEach { perm ->
        when (perm.permission) {

            Manifest.permission.CAMERA -> {
                when {
                    perm.status.isGranted -> {
                        Toast.makeText(
                            context, "Camera permission has been granted", Toast.LENGTH_SHORT
                        ).show()
                    }

                    perm.status.shouldShowRationale -> {
                        Toast.makeText(
                            context,
                            "Camera permission is needed to upload images",
                            Toast.LENGTH_SHORT
                        ).show()
                    }
                }
            }

            Manifest.permission.READ_MEDIA_IMAGES -> {
                when {
                    perm.status.isGranted -> {
                        Toast.makeText(
                            context, "Storage permission has been granted", Toast.LENGTH_SHORT
                        ).show()
                    }

                    perm.status.shouldShowRationale -> {
                        Toast.makeText(
                            context,
                            "Storage permission is needed to upload images",
                            Toast.LENGTH_SHORT
                        ).show()
                    }
                }
            }
        }
    }

    if (permissionState.allPermissionsGranted) {

        MyDialog(onDismiss = { showDialog = false }, showDialog = showDialog)

    }

}

@Composable
fun MyDialog(
    onDismiss: () -> Unit, showDialog: Boolean
) {

    if (showDialog) {

        Dialog(onDismissRequest = { onDismiss() }, content = {
            Box(
                modifier = Modifier.background(
                    shape = RoundedCornerShape(16.dp), color = Color.White
                )
            ) {

                Column(
                    modifier = Modifier
                        .padding(16.dp)
                        .fillMaxWidth(),
                    verticalArrangement = Arrangement.Center,

                    ) {
                    Text(text = "Material Dialog")
                    Spacer(modifier = Modifier.height(16.dp))
                    Text(text = "This is a simple Material Dialog.")
                    Spacer(modifier = Modifier.height(16.dp))
                    Button(
                        onClick = { onDismiss() },
                        modifier = Modifier.align(Alignment.CenterHorizontally)
                    ) {
                        Text("OK")
                    }
                }

            }

        }, properties = DialogProperties(
            dismissOnClickOutside = false, dismissOnBackPress = false
        )

        )
    }

}
问题分析与修复方案

核心问题点

  • runBlocking阻塞主线程:在生命周期观察者里用runBlocking会卡死UI线程,导致Composable重组异常,对话框根本没法正常渲染。
  • 对话框显示逻辑混乱:showDialog初始值设为true,但只有权限全授予时才显示对话框。权限请求完成前,对话框不显示;一旦权限通过,showDialog触发显示,但此时重组逻辑没控制好,直接闪一下就没。
  • Toast在Composable中重复执行:每次重组都会跑一遍Toast代码,不仅弹多次提示,还干扰UI渲染流程。
  • 权限请求线程错误:在Dispatchers.Default后台线程调用权限请求,这类系统弹窗必须在UI线程执行。

修复后的代码

@RequiresApi(Build.VERSION_CODES.TIRAMISU)
@OptIn(ExperimentalPermissionsApi::class)
@Composable
fun PermissionHandling() {
    val context = LocalContext.current
    val permissionState = rememberMultiplePermissionsState(
        permissions = listOf(Manifest.permission.CAMERA, Manifest.permission.READ_MEDIA_IMAGES)
    )
    val lifecycleOwner = LocalLifecycleOwner.current
    var showSuccessDialog by remember { mutableStateOf(false) }

    // 用LaunchedEffect监听生命周期,在STARTED状态发起权限请求,避免阻塞主线程
    LaunchedEffect(lifecycleOwner) {
        lifecycleOwner.lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
            permissionState.launchMultiplePermissionRequest()
        }
    }

    // 监听权限状态变化,仅在状态改变时执行提示逻辑
    LaunchedEffect(permissionState.permissions) {
        permissionState.permissions.forEach { perm ->
            when (perm.permission) {
                Manifest.permission.CAMERA -> {
                    when {
                        perm.status.isGranted -> {
                            Toast.makeText(context, "相机权限已授予", Toast.LENGTH_SHORT).show()
                        }
                        perm.status.shouldShowRationale -> {
                            Toast.makeText(context, "需要相机权限以上传图片", Toast.LENGTH_SHORT).show()
                        }
                    }
                }
                Manifest.permission.READ_MEDIA_IMAGES -> {
                    when {
                        perm.status.isGranted -> {
                            Toast.makeText(context, "存储权限已授予", Toast.LENGTH_SHORT).show()
                        }
                        perm.status.shouldShowRationale -> {
                            Toast.makeText(context, "需要存储权限以上传图片", Toast.LENGTH_SHORT).show()
                        }
                    }
                }
            }
        }
        // 所有权限授予后,触发对话框显示
        if (permissionState.allPermissionsGranted) {
            showSuccessDialog = true
        }
    }

    // 显示成功对话框
    if (showSuccessDialog) {
        MyDialog(onDismiss = { showSuccessDialog = false })
    }
}

@Composable
fun MyDialog(onDismiss: () -> Unit) {
    Dialog(
        onDismissRequest = { onDismiss() },
        properties = DialogProperties(
            dismissOnClickOutside = false,
            dismissOnBackPress = false
        )
    ) {
        Box(
            modifier = Modifier
                .background(shape = RoundedCornerShape(16.dp), color = Color.White)
        ) {
            Column(
                modifier = Modifier
                    .padding(16.dp)
                    .fillMaxWidth(),
                verticalArrangement = Arrangement.Center,
                horizontalAlignment = Alignment.CenterHorizontally
            ) {
                Text(text = "操作成功")
                Spacer(modifier = Modifier.height(16.dp))
                Text(text = "所有权限已成功授予")
                Spacer(modifier = Modifier.height(16.dp))
                Button(onClick = { onDismiss() }) {
                    Text("确定")
                }
            }
        }
    }
}

额外优化建议

  • 不要手动传递Context,改用LocalContext.current获取,符合Compose的状态管理规范。
  • 把Toast提示换成Compose的Snackbar,更适配Compose的UI生命周期,避免重复弹出。
  • 检查Jetpack Compose相关依赖版本,确保使用最新稳定版,比如androidx.compose.ui:ui:1.6.0及对应权限库版本。

内容的提问来源于stack exchange,提问作者Milos Stanojevic

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 22:48:11