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

在onClick/onComplete中启动Jetpack Compose AlertDialog报错求助

解决Jetpack Compose中FirebaseAuth回调调用Composable组件的注解不匹配问题

问题场景

我正在将现有Kotlin应用迁移至Kotlin MultiPlatform与Jetpack Compose,在登录流程中用FirebaseAuth实现用户登录时遇到注解不匹配错误:在signInWithEmailAndPassword的onComplete回调方法中添加@Composable注解并调用自定义ComposeAlert组件,触发如下错误:

"@Composable annotation mismatch with overridden function @Optin @Composable public open fun onComplete(task: Task<AuthResult?>: Unit defined in com.grgmobilesolutions.mycomposeapplication.android.Login.signInUser.', public abstract fun onComplete @NonNull p() Task<AuthResult?>: Unit defined in com.google.android.gms.tasks.onCompleteListener"

同类错误也出现在非Composable监听函数(如onClick)中调用Composable组件的场景。

错误原因

  • OnCompleteListener的onComplete是普通回调方法,不属于Compose重组作用域,父接口方法签名没有@Composable注解,重写时添加会导致签名不匹配。
  • Composable组件必须在Compose重组上下文中调用,只能在带@Composable注解的函数、Lambda或Compose提供的作用域内执行。

解决方案

核心思路:通过可观察状态变量触发Compose重组,在Compose UI树中根据状态判断是否显示弹窗,而非直接在非Composable回调中调用Composable组件。

步骤1:定义状态变量

用mutableStateOf创建控制弹窗显示/隐藏的可观察状态(推荐放在ViewModel中,避免配置变更丢失状态):

// 在Composable函数或ViewModel中定义
val openAlertDialog = remember { mutableStateOf(false) }

步骤2:修改FirebaseAuth回调逻辑

在回调中仅更新状态变量,不直接调用Composable组件:

private fun signInUser(mEmail: String?, mPassword: String?) {
    val c = Calendar.getInstance()
    val df = SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS a z")
    val currentDateAndTime1 = df.format(c.time)
    Log.i("", "Login: signInUser started at $currentDateAndTime1")
    Log.i("", "Login signInUser: user= $user")
    Log.i("", "Login signInUser: email= $mEmail password= $mPassword")
    val mAuth = FirebaseAuth.getInstance()

    mAuth.signInWithEmailAndPassword(mEmail!!, mPassword!!)
        .addOnCompleteListener { task ->
            if (task.isSuccessful || user != null) {
                // 仅更新状态,触发Compose重组
                openAlertDialog.value = true
                // ...其他业务逻辑
            }
        }
}

步骤3:在Compose UI树中渲染弹窗

在带@Composable注解的UI函数中,根据状态变量的值决定是否显示弹窗:

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun LoginScreen() {
    // ...其他UI代码

    // 根据状态显示弹窗
    if (openAlertDialog.value) {
        ComposeAlert(
            onDismissRequest = { openAlertDialog.value = false },
            onConfirmation = { openAlertDialog.value = false },
            dialogTitle = "Remove Family Administrator",
            dialogText = "Please confirm you want to be removed as a family administrator on this device",
            icon = Icons.Default.Info
        )
    }
}

保留原ComposeAlert组件

无需修改已定义的ComposeAlert:

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun ComposeAlert(
    onDismissRequest: () -> Unit,
    onConfirmation: () -> Unit,
    dialogTitle: String,
    dialogText: String,
    icon: ImageVector,
) {
    AlertDialog(
        icon = {
            Icon(icon, contentDescription = "Example Icon")
        },
        title = {
            Text(text = dialogTitle)
        },
        text = {
            Text(text = dialogText)
        },
        onDismissRequest = {
            onDismissRequest()
        },
        confirmButton = {
            TextButton(
                onClick = {
                    onConfirmation()
                }
            ) {
                Text("OK")
            }
        },
        dismissButton = {
            TextButton(
                onClick = {
                    onDismissRequest()
                }
            ) {
                Text("Cancel")
            }
        }
    )
}

注意事项

  • 状态变量推荐放在ViewModel中,避免屏幕旋转等配置变更导致状态丢失。
  • 所有Composable组件必须在Compose重组作用域内调用,非Composable回调只能通过修改状态触发UI更新。
  • 不要在非Composable函数中添加@Composable注解,重写父类/接口方法时必须严格匹配原方法签名。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 21:04:57