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

Android Firebase多图并行上传后,如何在awaitAll后执行单次操作

问题分析与解决方案

你的核心问题是并行上传图片后,后续的帖子上传逻辑未执行,主要原因包括共享集合的线程不安全操作、协程异常未捕获以及Firebase回调与协程的混用。以下是修正后的实现方案:

修正后的代码

lifecycleScope.launch {
    try {
        val uploadPhoto = UploadPhoto(storage, db)

        // 每个异步任务返回上传成功的URL,失败则返回null
        val uploadTasks = localUris.map { uri ->
            async(Dispatchers.IO) {
                when(val result = uploadPhoto.addPostToFireStore(uri)) {
                    is Response.Loading -> {
                        // 切换主线程更新进度UI
                        withContext(Dispatchers.Main) {
                            // TODO 显示进度条
                        }
                    }
                    is Response.Success -> result.data // 返回成功的远程URL
                    is Response.Failure -> {
                        Log.e("UploadError", "图片上传失败: ${result.e.message}", result.e)
                        null // 失败返回null,不终止整体流程
                    }
                }
            }
        }

        // 等待所有上传任务完成,过滤出成功的URL
        val remoteUris = uploadTasks.awaitAll().filterNotNull()

        // 确保有有效URL再执行帖子上传(可根据业务需求调整)
        if (remoteUris.isNotEmpty()) {
            val newPostKey = FirebaseDatabase.getInstance().reference.child("posts").push().key
            val postData = hashMapOf(
                "text" to text,
                "id" to newPostKey,
                "images" to remoteUris,
                "user" to getUser()!!.uid,
                "date" to FieldValue.serverTimestamp()
            )

            // 用协程挂起函数替代Firebase回调,确保流程同步
            try {
                db.collection("posts").add(postData).await()
                Log.d("PostLog", "帖子发布成功")
            } catch (e: Exception) {
                Log.e("PostError", "帖子发布失败", e)
            }
        } else {
            Log.w("UploadWarn", "无成功上传的图片,跳过帖子发布")
        }
    } catch (e: Exception) {
        Log.e("CoroutineError", "协程执行异常", e)
    }
}

关键改进点

  1. 线程安全的结果收集
    不再在多线程环境下直接修改共享的remoteUris集合,而是让每个async任务返回独立结果,awaitAll()后统一过滤收集,避免并发修改导致的数据异常。

  2. 全局异常捕获
    外层添加try-catch捕获协程整体异常,单个上传失败仅返回null,不会终止整个流程(可根据业务需求调整为终止逻辑)。

  3. Firebase回调转挂起函数
    使用await()替代addOnSuccessListener,需要依赖kotlinx-coroutines-play-services库,让代码在协程内同步执行,避免回调嵌套,同时统一捕获异常。

  4. UI线程安全更新
    进度条等UI操作需通过withContext(Dispatchers.Main)切换到主线程执行,避免跨线程操作UI的崩溃。

依赖补充

若使用await()方法,需在项目的build.gradle中添加以下依赖:

implementation "org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.7.3"

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 17:25:25