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

如何使用Async & Await让程序等待Firestore读取用户名存入postMap后执行后续操作

问题根因

你当前代码存在两个核心问题:

  • 取用户名使用了addSnapshotListener实时监听,你仅需单次获取数据无需监听,改用get()方法即可,还能避免内存泄漏
  • 上传Posts集合的逻辑写在了获取用户名的异步回调外侧,还没拿到用户名就已经执行了上传,自然无法正确写入username字段

你可以通过Kotlin协程+Firebase KTX扩展提供的await()方法简化异步逻辑,实现按顺序执行,具体实现如下:


步骤1:添加必要依赖

先确认模块级build.gradle里已经添加以下依赖:

// 协程依赖
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3"
// Firebase KTX扩展,支持await()方法
implementation "com.google.firebase:firebase-firestore-ktx:24.10.0"
implementation "com.google.firebase:firebase-storage-ktx:20.3.0"

步骤2:优化后业务代码

if(selectedPicture != null){
    // Activity/Fragment直接用lifecycleScope启动协程即可
    lifecycleScope.launch {
        try {
            // 1. 上传图片,await()会等待操作完成再走下一步
            imageReference.putFile(selectedPicture!!).await()
            val uploadPictureReference = storage.reference.child("images").child(imageName)
            val downloadUrl = uploadPictureReference.downloadUrl.await().toString()

            val currentUser = auth.currentUser ?: return@launch
            // 2. 构造基础postMap
            val postMap = hashMapOf<String,Any>(
                "downloadUrl" to downloadUrl,
                "userEmail" to currentUser.email!!,
                "comment" to binding.uploadCommentText.text.toString(),
                "date" to Timestamp.now()
            )

            // 3. 等待用户名获取完成
            val userSnapshot = db.collection("UserDetails").get().await()
            if (!userSnapshot.isEmpty) {
                for (document in userSnapshot.documents) {
                    val username = document.getString("username") ?: continue
                    postMap["username"] = username
                    // 如果UserDetails每个用户仅存一条数据,拿到后直接中断循环即可
                    break
                }
            }

            // 4. 用户名写入完成后再上传Posts集合
            firestore.collection("Posts").add(postMap).await()
            // 上传成功结束页面
            finish()
        } catch (e: Exception) {
            // 统一捕获所有流程的异常,无需重复写失败回调
            Toast.makeText(this@你的Activity类名, e.localizedMessage, Toast.LENGTH_LONG).show()
        }
    }
}

可选方案:不引入协程的回调写法

如果你暂时不想用协程,直接调整原有代码的逻辑顺序即可,把上传Posts的代码移到获取用户名的回调内部:

//Get Username from firestore and put it into postMap
db.collection("UserDetails").get().addOnSuccessListener { value ->
    if(!value.isEmpty){
        val documents = value.documents
        for (document in documents){
            val username = document.get("username") as String
            postMap.put("username",username)
        }
    }
    // 拿到用户名之后再执行上传
    firestore.collection("Posts").add(postMap).addOnSuccessListener {
        finish()
    }.addOnFailureListener{
        Toast.makeText(this,it.localizedMessage,Toast.LENGTH_LONG).show()
    }
}.addOnFailureListener{
    Toast.makeText(this,it.localizedMessage,Toast.LENGTH_LONG).show()
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 08:24:06