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

为何CoroutineScope未等待Firebase数据获取完成就执行后续代码?

解决协程异步加载Firebase数据导致ListView显示空列表的问题

核心问题分析

你当前的代码逻辑存在异步操作与UI操作不同步的问题:

  • 在Dispatchers.IO协程中异步拉取Firebase数据时,主线程的UI代码(创建Adapter、设置ListView)会直接执行,此时list还是初始的空列表,自然显示为空。
  • 你尝试把UI代码移到协程里报错,是因为UI操作必须在主线程执行,而你用的是Dispatchers.IO,直接操作View会抛出异常。

代码修复步骤

1. 用生命周期感知协程Scope同步数据与UI

不要手动创建CoroutineScope,改用Android提供的lifecycleScope(Activity中)或viewLifecycleOwner.lifecycleScope(Fragment中),它会自动绑定组件生命周期,避免内存泄漏:

// Activity中直接使用lifecycleScope
lifecycleScope.launch {
    val customList = mutableListOf<CustomClass>()
    StartPageActivity.customClassExpandList.forEach {
        if (it.title.contains(CustomClass.title)) {
            customList.add(getFirebaseData(it.date))
            // 收集到12条数据后停止遍历
            if (customList.size == 12) return@forEach
        }
    }
    // 切换到主线程更新UI
    withContext(Dispatchers.Main) {
        val listAdapter = MyListAdapter(context, customList)
        listView.adapter = listAdapter
        listView.visibility = View.VISIBLE
        listView.dividerHeight = 0
        listView.layoutParams.height = calculateHeight(listView, 12)
    }
}

2. 修正getFirebaseData的逻辑错误

你的挂起函数存在变量名错误和回调嵌套问题,导致数据无法正确更新:

suspend fun getFirebaseData(date: LocalDate): CustomClass = withContext(Dispatchers.IO) {
    val customClass = CustomClass("$date", date, "Empty", false)
    // 直接用await()获取结果,无需嵌套addOnCompleteListener
    val document = FirebaseFirestore.getInstance()
        .collection("users")
        .document(FirebaseAuth.getInstance().currentUser!!.uid)
        .collection("customClass")
        .document(date.toString())
        .get()
        .await()
    
    if (document.exists()) {
        // 修正变量名错误:goal→customClass,修复字段拼写错误:tile→title
        customClass.description = document["description"].toString()
        customClass.title = document["title"].toString()
    }
    return@withContext customClass
}

修复点说明:

  • 移除addOnCompleteListener:await()会直接等待任务完成并返回结果,回调嵌套会导致你修改的变量和返回的customClass不是同一个对象。
  • 修正变量名错误:你定义的是customClass,却错误地写了goal。
  • 修复字段拼写错误:把tile改为title,避免获取不到正确数据。

3. 额外优化建议

  • 避免直接访问StartPageActivity的静态列表,建议通过ViewModel传递数据,符合MVVM架构规范。
  • 可以用async+awaitAll并行拉取Firebase数据,提升加载速度:
// 并行加载示例
val deferredList = StartPageActivity.customClassExpandList
    .filter { it.title.contains(CustomClass.title) }
    .take(12) // 直接取前12条,无需遍历判断size
    .map { async { getFirebaseData(it.date) } }
val customList = deferredList.awaitAll()

内容的提问来源于stack exchange,提问作者J. Weidenhagen

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 12:20:32