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

Kotlin中Firebase的addOnSuccessListener返回值滞后无法正确判断用户是否已提交餐厅点评

问题根源

Firebase Firestore 的查询属于异步非阻塞操作,addOnSuccessListener 是查询完成后的回调函数,不会阻塞主线程执行。你调用 fetchIfDataExist 后,主线程不会等待查询结束,会直接执行后续的 Log 打印和 if 判断逻辑,此时回调还没触发,existingReview 自然还是初始值 false。

解决方案

有两种常用的实现方式,你可以根据项目技术栈选择:

方案1:接口回调(无额外依赖,适配所有项目)

步骤1:定义回调接口

interface OnReviewCheckCallback {
    fun onCheckResult(isExisting: Boolean)
}

步骤2:改造 fetchIfDataExist 函数

移除全局变量 existingReview,将回调作为入参,查询完成后通过回调返回结果:

private fun fetchIfDataExist(restaurant: String, callback: OnReviewCheckCallback) {
    Log.d("URL_DEBUG", "restaurant name: $restaurant")
    var isExisting = false
    FirebaseFirestore.getInstance().collection("user_review")
        .get()
        .addOnSuccessListener { result ->
            loop@ for (document in result) {
                if (document.id.contains(email)) {
                    val user = document.toObject(User_Review::class.java)
                    if (user.restaurant == restaurant) {
                        isExisting = true
                        break@loop
                    }
                }
            }
            callback.onCheckResult(isExisting)
        }
        .addOnFailureListener {
            Toast.makeText(this, "查询点评记录失败", Toast.LENGTH_LONG).show()
            // 失败时可按业务需求返回默认值,这里默认返回未提交
            callback.onCheckResult(false)
        }
}

步骤3:调整调用逻辑

把原来后续的判断逻辑全部移到回调实现中:

if (email == "guest_email") {
    showAlertAuth()
} else {
    fetchIfDataExist(placeName, object : OnReviewCheckCallback {
        override fun onCheckResult(isExisting: Boolean) {
            Log.d("URL_DEBUG", "fuera: $isExisting")
            if (isExisting) {
                showAlertExistingReview()
            } else {
                val intent = Intent(this@你当前的Activity类名, ReviewActivity::class.java).apply {
                    putExtra("email", email)
                    putExtra("restaurant", placeName)
                    putExtra("edit", false)
                }
                startActivity(intent)
            }
        }
    })
}

注意把代码里的你当前的Activity类名替换为你实际的Activity类名。

方案2:Kotlin 协程(代码更简洁,适合已接入协程的项目)

步骤1:引入 Firestore Ktx 扩展

在模块级 build.gradle 中添加依赖:

implementation "com.google.firebase:firebase-firestore-ktx:24.10.0" // 可替换为最新版本

步骤2:将 fetchIfDataExist 改造为挂起函数

private suspend fun fetchIfDataExist(restaurant: String): Boolean {
    Log.d("URL_DEBUG", "restaurant name: $restaurant")
    return try {
        val result = FirebaseFirestore.getInstance().collection("user_review").get().await()
        // 直接匹配符合条件的记录
        result.any { document ->
            document.id.contains(email) 
            && document.toObject(User_Review::class.java).restaurant == restaurant
        }
    } catch (e: Exception) {
        Toast.makeText(this, "查询点评记录失败", Toast.LENGTH_LONG).show()
        false
    }
}

步骤3:协程中调用函数

if (email == "guest_email") {
    showAlertAuth()
} else {
    lifecycleScope.launch {
        val existingReview = fetchIfDataExist(placeName)
        Log.d("URL_DEBUG", "fuera: $existingReview")
        if (existingReview) {
            showAlertExistingReview()
        } else {
            val intent = Intent(this@你当前的Activity类名, ReviewActivity::class.java).apply {
                putExtra("email", email)
                putExtra("restaurant", placeName)
                putExtra("edit", false)
            }
            startActivity(intent)
        }
    }
}

性能优化建议

你当前的实现会拉取user_review集合的全量数据再过滤,数据量增大后性能会很差,建议直接使用Firestore的条件查询提前过滤,避免全表扫描:

// 示例:直接查询对应用户+对应餐厅的记录,不需要拉取全量数据
FirebaseFirestore.getInstance().collection("user_review")
    .whereEqualTo("restaurant", restaurant)
    // 如果你的文档ID直接是用户邮箱,可以再加条件.whereEqualTo(FieldPath.documentId(), email),性能提升更明显
    .get()

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 23:15:00