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

使用Kotlin Coroutines从Firestore获取数据为空问题求助

排查Kotlin协程从Firestore获取数据为空的问题

我在使用Kotlin Coroutines从Firestore获取数据时,Log.d("Products", products.toString())返回空值,通过Toast查看结果数量显示为0,且Logcat无任何错误信息。以下是我的代码及Firestore结构,恳请帮忙排查原因:

SearchItemActivity代码

import android.os.Bundle
import android.util.Log
import android.widget.GridView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.google.firebase.Firebase
import com.google.firebase.firestore.DocumentSnapshot
import com.google.firebase.firestore.firestore
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.tasks.await

class SearchItemActivity : AppCompatActivity() {
    private val db = Firebase.firestore
    private val products: MutableList<DocumentSnapshot> = mutableListOf()
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_search_item)

        val gridView = findViewById<GridView>(R.id.itemGridView)

        CoroutineScope(Dispatchers.Main).launch {
            try {
                val result = db.collection("product").get().await()
                Toast.makeText(this@SearchItemActivity, "Number of documents in 'product' collection: ${result.size()}", Toast.LENGTH_SHORT).show()
                for (document in result) {
                    val uid = document.id
                    val results = db.collection("product").document(uid).collection("products").get().await()
                    products.addAll(results.documents)
                }
                val adapter = ItemUserAdapter(this@SearchItemActivity, layoutInflater, products)
                gridView.adapter = adapter
            } catch (e: Exception) {
                Toast.makeText(this@SearchItemActivity, e.localizedMessage, Toast.LENGTH_SHORT).show()
            }
        }

        Log.d("Products", products.toString())

        gridView.setOnItemClickListener { parent, view, position, id ->
            val product = parent.getItemAtPosition(position) as DocumentSnapshot
            Toast.makeText(applicationContext, "UID: ${product.id}", Toast.LENGTH_SHORT).show()
        }
    }
}

Firestore结构

  • 集合内的子集合:
    集合内的子集合
  • Products内部结构:
    Products内部结构

问题排查与解决方案

1. 异步执行顺序问题

当前Log.d("Products", products.toString())在协程启动后立即执行,而Firestore请求是异步操作,此时products还未被填充,导致日志为空。将Log语句移到协程内部、数据填充完成之后:

CoroutineScope(Dispatchers.Main).launch {
    try {
        val result = db.collection("product").get().await()
        Toast.makeText(this@SearchItemActivity, "Number of documents in 'product' collection: ${result.size()}", Toast.LENGTH_SHORT).show()
        for (document in result) {
            val uid = document.id
            val results = db.collection("product").document(uid).collection("products").get().await()
            products.addAll(results.documents)
        }
        // 移至此处打印日志
        Log.d("Products", products.toString())
        val adapter = ItemUserAdapter(this@SearchItemActivity, layoutInflater, products)
        gridView.adapter = adapter
    } catch (e: Exception) {
        Toast.makeText(this@SearchItemActivity, e.localizedMessage, Toast.LENGTH_SHORT).show()
    }
}

2. Firestore集合路径不匹配(核心问题)

从截图可见,根集合是Projects,但代码中使用的是db.collection("product"),路径完全不匹配:

  • 截图根集合为Projects,而非product
  • 每个Projects文档下的子集合是products

修正集合路径:

// 将db.collection("product")改为db.collection("Projects")
val result = db.collection("Projects").get().await()
for (document in result) {
    val uid = document.id
    // 子集合路径对应Projects/{docId}/products
    val results = db.collection("Projects").document(uid).collection("products").get().await()
    products.addAll(results.documents)
}

3. 隐性权限问题

若路径修正后仍无数据,检查Firestore安全规则。默认规则仅允许认证用户读取,未登录时请求会静默失败(无错误日志)。可临时修改规则测试:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if true; // 测试用,上线需恢复安全规则
    }
  }
}

4. 协程作用域优化

建议使用lifecycleScope替代手动创建的CoroutineScope(Dispatchers.Main),避免内存泄漏:

// 需先导入依赖:implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.6.2"
lifecycleScope.launch {
    // 内部代码保持不变
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 03:20:29