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

如何在Jetpack Compose中检查Firestore数据库中用户名是否存在

解决Firestore异步检查用户名存在的问题

你的核心问题是Firestore的查询是异步操作,原userExists函数在回调执行前就直接返回了初始的false,导致判断逻辑完全失效。下面是具体的修复方案:

1. 重构userExists为挂起函数

把同步函数改成挂起函数,用await()替代回调,确保等待查询完成后再返回结果:

import kotlinx.coroutines.tasks.await

suspend fun userExists(fieldName: String, fieldValue: String): Boolean {
    val db = FirebaseFirestore.getInstance()
    val dbUsers = db.collection("user")
    
    val querySnapshot = dbUsers.whereEqualTo(fieldName, fieldValue).get().await()
    // 文档不为空说明用户名已存在
    return querySnapshot.documents.isNotEmpty()
}

2. 在Composable中用协程执行异步检查

Jetpack Compose的点击事件是普通lambda,不能直接调用挂起函数,需要用rememberCoroutineScope启动协程,同时建议添加加载状态避免重复点击:

修改SignUpScreen的代码:

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun SignUpScreen(navigation: NavController, auth: FirebaseAuth) {
    var userName by remember { mutableStateOf("") }
    var userEmail by remember { mutableStateOf("") }
    var password by rememberSaveable { mutableStateOf("") }
    var passwordVisible by rememberSaveable { mutableStateOf(false) }
    // 添加加载状态,防止重复点击
    var isLoading by remember { mutableStateOf(false) }
    val context = LocalContext.current
    val sharedPrefMail = context.getSharedPreferences("userEmail", Context.MODE_PRIVATE)
    val sharedPrefName = context.getSharedPreferences("userName", Context.MODE_PRIVATE)
    val sharedPrefScore = context.getSharedPreferences("highScore", Context.MODE_PRIVATE)
    // 获取Composable安全的协程Scope
    val coroutineScope = rememberCoroutineScope()

    val buttonSize = with(LocalDensity.current) {
        (300f).toDp()
    }

    Column(
        modifier = Modifier
            .fillMaxSize()
            .padding(vertical = buttonSize),
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        // ... 保留原有的输入UI代码 ...

        Button(
            onClick = {
                coroutineScope.launch {
                    if (isLoading) return@launch // 加载中不重复执行
                    isLoading = true

                    when {
                        userEmail.isEmpty() || password.isEmpty() || userName.isEmpty() -> {
                            Toast.makeText(context, "请输入邮箱、用户名和密码", Toast.LENGTH_LONG).show()
                        }
                        userExists("userName", userName) -> {
                            Toast.makeText(context, "用户名已被使用", Toast.LENGTH_LONG).show()
                        }
                        else -> {
                            auth.createUserWithEmailAndPassword(userEmail, password)
                                .addOnSuccessListener {
                                    val user = UserObj(userEmail, userName, "0")
                                    FirebaseFirestore.getInstance().collection("user")
                                        .add(user)
                                        .addOnSuccessListener {
                                            Toast.makeText(context, "用户创建成功", Toast.LENGTH_LONG).show()
                                            sharedPrefMail.edit().putString("userMail", userEmail).apply()
                                            sharedPrefName.edit().putString("userName", userName).apply()
                                            sharedPrefScore.edit().putString("highScore", "0").apply()
                                            navigation.navigate("FirstScreen")
                                        }
                                        .addOnFailureListener {
                                            Toast.makeText(context, "用户创建失败", Toast.LENGTH_LONG).show()
                                        }
                                }
                                .addOnFailureListener {
                                    Toast.makeText(context, "无法创建用户:${it.localizedMessage}", Toast.LENGTH_LONG).show()
                                }
                        }
                    }
                    isLoading = false // 结束加载状态
                }
            },
            modifier = Modifier.size(buttonSize, buttonSize/3),
            enabled = !isLoading // 加载中禁用按钮
        ) {
            Text(if (isLoading) "处理中..." else "注册")
        }
    }
}

关键修复点说明

  • 用await()替代addOnSuccessListener:挂起函数会等待Firestore查询完成,确保返回正确的用户名存在状态。
  • 用rememberCoroutineScope启动协程:在Composable中安全执行异步操作,避免内存泄漏。
  • 添加加载状态:防止用户重复点击,同时给用户明确的操作反馈。
  • 调整逻辑顺序:确保用户名检查完成后,再执行后续的注册流程。

内容的提问来源于stack exchange,提问作者Yunus Emrah Uluçay

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 16:53:11