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

如何让Kotlin函数等待Firestore数据库获取数据后再返回结果

解决Firestore异步获取数据返回空列表的问题

你遇到的问题根源在于Firestore的get()是异步操作,原代码里的addOnSuccessListener会在后台线程执行,而函数会直接跳过回调逻辑提前返回空的exercisesList。用.await()结合Kotlin协程可以让函数等待数据获取完成后再返回结果,具体修改如下:

修改后的代码

import kotlinx.coroutines.tasks.await
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext

suspend fun getExercise(bodyPart: String): MutableList<String> {
    val db = Firebase.firestore
    val exercisesList = mutableListOf<String>()

    return try {
        // 构建查询并使用.await()等待结果返回
        val queryResult = db.collection("exercises")
            .whereEqualTo("body-part", bodyPart)
            .get()
            .await()
        
        // 遍历结果填充列表
        for (doc in queryResult) {
            exercisesList.add(doc.id)
            Log.d(TAG, "${doc.id} => ${doc.data}")
        }
        exercisesList
    } catch (exception: Exception) {
        // 捕获查询异常并打印日志
        Log.w(TAG, "Error getting documents: ", exception)
        // 异常时返回空列表,也可根据需求抛出异常
        exercisesList
    }
}

关键修改说明

  • 给函数添加suspend修饰符:.await()是挂起函数,只能在挂起函数或协程作用域内调用,所以必须给getExercise加上该修饰符。
  • 用.await()替代回调:query.get().await()会让协程暂停,直到Firestore返回查询结果,避免函数提前返回空列表。
  • 用try-catch处理异常:替代原代码的addOnFailureListener,统一捕获查询过程中可能出现的错误。
  • (可选)IO线程执行:如果希望数据库操作不阻塞主线程,可以把逻辑包裹在withContext(Dispatchers.IO)中:
    suspend fun getExercise(bodyPart: String): MutableList<String> {
        val db = Firebase.firestore
        return withContext(Dispatchers.IO) {
            val exercisesList = mutableListOf<String>()
            try {
                val queryResult = db.collection("exercises")
                    .whereEqualTo("body-part", bodyPart)
                    .get()
                    .await()
                for (doc in queryResult) {
                    exercisesList.add(doc.id)
                    Log.d(TAG, "${doc.id} => ${doc.data}")
                }
            } catch (exception: Exception) {
                Log.w(TAG, "Error getting documents: ", exception)
            }
            exercisesList
        }
    }
    

调用注意事项

因为这是挂起函数,不能直接在普通非挂起函数中调用,需要在协程作用域内执行,比如:

// 在Activity/Fragment中使用lifecycleScope
lifecycleScope.launch {
    val chestExercises = getExercise("chest")
    // 在此处使用获取到的训练列表
}

// 在ViewModel中使用viewModelScope
viewModelScope.launch {
    val legExercises = getExercise("legs")
    // 更新UI或处理数据
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 14:40:15