如何使用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
相关产品推荐
相关产品推荐

