Kotlin调用Firestore为何跳过代码段?用户存在校验函数异常
问题根源:Firestore的异步操作“抢先一步”返回了结果
你写的这个函数之所以失效,核心原因是Firestore的get()方法是异步执行的——它不会卡在第3行等网络请求拿到结果,而是直接跳到第6行返回初始的false,等到真正从Firestore拿到数据触发addOnSuccessListener(也就是第4行)的时候,函数早就把结果返回出去了,这时候修改res自然没意义。
两种靠谱的解决方案
针对Kotlin项目,我推荐两种处理方式,你可以根据自己的项目情况选择:
方式一:用Kotlin协程让异步代码“看起来像同步”(最推荐)
协程是Kotlin处理异步的最佳实践,能让代码逻辑更清晰。首先确保你已经添加了Firestore的协程依赖(如果没加,去项目的build.gradle里补一下implementation "org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.7.3"这类依赖),然后修改函数为挂起函数:
import kotlinx.coroutines.tasks.await private suspend fun usernameRepeated(db: FirebaseFirestore, username: String): Boolean { return try { // 用await()等待异步请求完成,拿到结果再返回 val queryResult = db.collection("User") .whereEqualTo("username", username) .get() .await() queryResult.documents.isNotEmpty() } catch (e: Exception) { // 网络错误或者其他异常时,返回false或者根据需求处理 false } }
调用这个函数的时候,需要在协程作用域里(比如ViewModel用viewModelScope,Activity/Fragment用lifecycleScope):
// 举个在ViewModel里调用的例子 viewModelScope.launch { val isUsernameTaken = usernameRepeated(db, "你的用户名") // 这里拿到结果后再做后续操作,比如提示用户用户名已存在 if (isUsernameTaken) { // 处理用户名重复的情况 } else { // 用户名可用,继续流程 } }
方式二:用回调函数接收结果
如果暂时不想用协程,也可以通过回调的方式把结果传回来,避免同步返回的问题:
private fun usernameRepeated(db: FirebaseFirestore, username: String, onCheckCompleted: (Boolean) -> Unit) { db.collection("User") .whereEqualTo("username", username) .get() .addOnSuccessListener { snapshot -> // 拿到结果后通过回调传递出去 onCheckCompleted(snapshot.documents.isNotEmpty()) } .addOnFailureListener { // 请求失败时,也通过回调告知结果(比如返回false) onCheckCompleted(false) } }
调用的时候这样写:
usernameRepeated(db, "你的用户名") { isRepeated -> // 在这里处理检查结果 if (isRepeated) { println("用户名已经被占用啦") } else { println("用户名可用!") } }
再理一遍你原来代码的执行顺序
帮你捋清楚为什么断点会出现那种情况:
- 执行第2行,
res被设为false - 执行第3行,发起Firestore的异步请求,然后不等待结果直接跳到第6行
- 执行第6行,返回
res(此时还是初始的false) - 过了一会儿,Firestore请求完成,才会触发
addOnSuccessListener执行第4行,但这时候函数早就返回了,修改res也没用了
所以核心就是:异步操作不能用同步的方式返回结果,必须用协程、回调这类异步处理模式。
内容的提问来源于stack exchange,提问作者Chema
相关产品推荐
相关产品推荐

