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

Jetpack Compose报错:@Composable调用仅能在Composable上下文执行(谷歌登录)

解决Android Jetpack Compose谷歌登录中的@Composable invocations can only happen from the context of a @Composable function错误

错误原因

  • googleSignIn被标记为@Composable函数,但在OutlinedButton的onClick回调中调用它——onClick的lambda属于非Composable上下文,不允许调用Composable函数。
  • rememberLauncherForActivityResult必须在Composable作用域内初始化,但启动登录Intent的操作可以在普通lambda中执行。

解决方案

拆分谷歌登录的职责,将Composable相关的初始化逻辑放在正确的作用域内,把登录逻辑和结果处理封装为普通函数,确保context能正常传递使用:

修改后的loginButton函数

@Composable
fun loginButton(loginType: Int, context: Context, googleSignInClient: GoogleSignInClient?) {
    // 在Composable作用域内初始化ActivityResultLauncher
    val signInLauncher = rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
        handleGoogleSignInResult(result, context)
    }

    Column(horizontalAlignment = Alignment.CenterHorizontally, modifier = Modifier.fillMaxWidth()) {
        if (loginType == 0) {
            OutlinedButton(
                onClick = {
                    // 调用普通函数启动谷歌登录,避免在非Composable上下文调用Composable
                    googleSignInLaunch(signInLauncher, googleSignInClient)
                },
                border = BorderStroke(2.dp, Color.Black),
                colors = ButtonDefaults.buttonColors(backgroundColor = Color(0xFFFFFFFF)),
                modifier = Modifier
                    .height(40.dp)
                    .width(300.dp),
                shape = RoundedCornerShape(50)
            ) {
                Image(
                    painter = painterResource(id = R.drawable.google_logo),
                    contentDescription = "Google Logo(Src: Wikipedia)"
                )
                Spacer(modifier = Modifier.width(30.dp))
                Text(text = "Sign in with Google", fontSize = 15.sp, color = Color.Black)
            }
        } else if (loginType == 1) {
            OutlinedButton(
                onClick = {},
                border = BorderStroke(2.dp, Color.Black),
                colors = ButtonDefaults.buttonColors(backgroundColor = Color(0xFFFFFFFF)),
                modifier = Modifier
                    .height(40.dp)
                    .width(300.dp),
                shape = RoundedCornerShape(50)
            ) {
                Image(
                    painter = painterResource(id = R.drawable.apple_logo),
                    contentDescription = "Apple Logo"
                )
                Spacer(modifier = Modifier.width(30.dp))
                Text(text = "Sign in with Apple", fontSize = 15.sp, color = Color.Black)
            }
        } else {
            Text("Cannot load the sign in button")
        }
    }
}

拆分后的谷歌登录逻辑函数(独立Kotlin文件)

import android.app.Activity
import android.content.Context
import android.content.Intent
import com.google.android.gms.auth.api.signin.GoogleSignIn
import com.google.android.gms.auth.api.signin.GoogleSignInAccount
import com.google.android.gms.common.api.ApiException
import com.google.android.gms.tasks.Task
import android.util.Log
import androidx.activity.result.ActivityResult
import androidx.activity.result.ActivityResultLauncher

// 处理谷歌登录结果,可直接使用传入的context
fun handleGoogleSignInResult(result: ActivityResult, context: Context) {
    if (result.resultCode == Activity.RESULT_OK) {
        val intent = result.data
        intent?.let {
            val task: Task<GoogleSignInAccount> = GoogleSignIn.getSignedInAccountFromIntent(it)
            try {
                val account = task.getResult(ApiException::class.java)
                Log.d("AuthManager", "FirebaseAuthWithGoogle" + account.id)
                // 此处可使用context执行后续操作,如跳转页面、显示Toast等
            } catch (e: ApiException) {
                e.printStackTrace()
                Log.w("LoginActivity", "Google sign in failed", e)
            }
        }
    }
}

// 启动谷歌登录Intent的普通函数
fun googleSignInLaunch(launcher: ActivityResultLauncher<Intent>, googleSignInClient: GoogleSignInClient?) {
    googleSignInClient?.signInIntent?.let {
        launcher.launch(it)
    }
}

修改说明

  1. 将rememberLauncherForActivityResult移到loginButton内部,确保它在Composable作用域中初始化,符合Jetpack Compose的规则。
  2. 把原googleSignIn中的结果处理逻辑拆分为普通函数handleGoogleSignInResult,直接接收context参数,可正常使用上下文做后续操作。
  3. 新增googleSignInLaunch函数负责启动登录Intent,在onClick的lambda中直接调用这个普通函数,规避了在非Composable上下文调用Composable函数的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 18:36:24