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

如何在Kotlin中等待Firestore查询完成后再执行后续操作?

问题:Firestore异步查询导致返回空列表,如何用Kotlin协程正确处理?

我是Firestore和Kotlin的新手,写了个函数想检索指定日期范围内的文档ID并存入列表,但函数总是返回空值。我知道这是因为Firestore查询是异步的,还没等查询完成函数就返回了。加3秒延迟能临时解决,但这明显不是好办法,网络慢的时候肯定会出问题。尝试用协程解决,但搞不懂怎么用。

原函数代码:

fun documentsBetweenDates(date1 : String, date2 : String) : MutableList<String> {
    val db = FirebaseFirestore.getInstance()
    val retrievedDocuments = mutableListOf<String>()

    db.collection("users").document(getUID())
        .collection("values")
        .whereGreaterThanOrEqualTo("purchaseDate", convertDateToMillis(date1)!!)
        .whereLessThanOrEqualTo("purchaseDate", convertDateToMillis(date2)!!)
        .get()
        .addOnSuccessListener { document ->
            for (documents in document) {
                retrievedDocuments.add(documents.id)
                Log.d("DB", "Document between dates found: ${retrievedDocuments}")
            }
        }

    return retrievedDocuments
}

Fragment中的调用代码:

var test = dbController.documentsBetweenDates("22/02/2021", "22/02/2022")
Log.d("DB", test.ToString())

解决方案:用Kotlin协程实现Firestore异步查询的同步调用

1. 原方法失效的核心原因

Firestore的get()是异步执行的,addOnSuccessListener内的逻辑要等查询完成后才会触发,但你的函数在调用get()后立刻返回了空的retrievedDocuments——这时候查询还在后台跑,列表根本没被填充。靠延迟“凑时间”完全不可靠,网络波动时必然出错。

2. 改造为协程挂起函数

Firebase官方支持Kotlin协程,只需把函数改成挂起函数,用await()替代回调,让协程自动等待查询完成:

// 新增suspend关键字,标记为协程挂起函数
suspend fun documentsBetweenDates(date1: String, date2: String): MutableList<String> {
    val db = FirebaseFirestore.getInstance()
    val retrievedDocuments = mutableListOf<String>()

    // 用await()替代addOnSuccessListener,协程会暂停直到查询返回结果
    val querySnapshot = db.collection("users").document(getUID())
        .collection("values")
        .whereGreaterThanOrEqualTo("purchaseDate", convertDateToMillis(date1)!!)
        .whereLessThanOrEqualTo("purchaseDate", convertDateToMillis(date2)!!)
        .get()
        .await() // 关键:阻塞协程直到查询完成

    // 查询完成后再遍历填充列表
    for (document in querySnapshot) {
        retrievedDocuments.add(document.id)
        Log.d("DB", "Document between dates found: ${retrievedDocuments}")
    }

    return retrievedDocuments
}

3. 在Fragment中正确调用挂起函数

挂起函数不能直接在主线程同步调用,需要借助协程作用域启动协程。推荐用Fragment自带的lifecycleScope(需依赖AndroidX Lifecycle库),它会自动和Fragment生命周期绑定,避免内存泄漏:

// 比如在Fragment的onViewCreated方法中调用
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    
    lifecycleScope.launch {
        val test = dbController.documentsBetweenDates("22/02/2021", "22/02/2022")
        Log.d("DB", test.toString())
        // 在这里处理获取到的列表,比如更新UI
    }
}

4. 必加的异常处理

Firestore查询可能因网络错误、权限不足等原因失败,建议用try-catch捕获异常:

suspend fun documentsBetweenDates(date1: String, date2: String): MutableList<String> {
    val db = FirebaseFirestore.getInstance()
    val retrievedDocuments = mutableListOf<String>()

    try {
        val querySnapshot = db.collection("users").document(getUID())
            .collection("values")
            .whereGreaterThanOrEqualTo("purchaseDate", convertDateToMillis(date1)!!)
            .whereLessThanOrEqualTo("purchaseDate", convertDateToMillis(date2)!!)
            .get()
            .await()

        for (document in querySnapshot) {
            retrievedDocuments.add(document.id)
            Log.d("DB", "Document between dates found: ${retrievedDocuments}")
        }
    } catch (e: Exception) {
        Log.e("DB", "查询失败: ${e.message}")
        // 可根据需求返回空列表、抛出异常或提示用户
    }

    return retrievedDocuments
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 23:10:50