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

如何用RxKotlin在Kotlin中同步执行循环完成Firebase上传与Firestore提交

解决方案

核心是用RxKotlin的序列操作符将异步任务转为可控的同步执行流程,确保每个反馈项的所有图片上传完成后再提交Firestore,所有反馈处理完毕后再清理本地数据。

步骤1:封装Firebase Task为Rx Single

给Firebase的Task添加扩展函数,方便转换成Rx的Single类型:

import com.google.android.gms.tasks.Task
import io.reactivex.Single
import io.reactivex.SingleEmitter

fun <T> Task<T>.toSingle(): Single<T> {
    return Single.create { emitter: SingleEmitter<T> ->
        this.addOnCompleteListener { task ->
            if (task.isSuccessful) {
                emitter.onSuccess(task.result!!)
            } else {
                emitter.onError(task.exception ?: Exception("Task failed without exception"))
            }
        }
    }
}

步骤2:重构图片上传与数据提交逻辑

修改uploadImageAndToFireBase方法,返回Single<Unit>,用Rx控制图片上传的顺序和URL收集:

private fun uploadImageAndToFireBase(
    feedbackModel: FeedbackModel,
    email: String,
    firstName: String,
    lastName: String,
    uuid: String
): Single<Unit> {
    // 无图片直接提交数据
    if (feedbackModel.imageList.isEmpty()) {
        return Single.fromCallable {
            uploadDataToFirebaseFeedbackDocument(feedbackModel, emptyList(), email, firstName, lastName, uuid)
        }
    }

    // 遍历图片列表,逐个上传并收集URL
    return Observable.fromIterable(feedbackModel.imageList.withIndex())
        .concatMapSingle { (index, imagePath) ->
            val ref = storageReference?.child("tests/feedback/images$index.jpg")
                ?: return@concatMapSingle Single.error<Uri>(Exception("Storage reference is null"))

            ref.putFile(Uri.parse(imagePath))
                .continueWithTask { ref.downloadUrl }
                .toSingle()
        }
        .toList() // 收集所有图片的下载URL
        .flatMap { listOfImagePath ->
            Single.fromCallable {
                uploadDataToFirebaseFeedbackDocument(feedbackModel, listOfImagePath, email, firstName, lastName, uuid)
            }
        }
}

步骤3:重构批量反馈发送逻辑

修改sendListOfFeedBack方法,用concatMap保证每个反馈项顺序执行,全部完成后再清理本地数据:

private fun sendListOfFeedBack(
    listOfFeedBack: ArrayList<FeedbackModel>,
    email: String,
    firstName: String,
    lastName: String,
    uuid: String
): Single<String?> {
    return if (checkNetworkDataAvailableOrNot()) {
        Observable.fromIterable(listOfFeedBack)
            .concatMapSingle { feedbackModel ->
                uploadImageAndToFireBase(feedbackModel, email, firstName, lastName, uuid)
            }
            .ignoreElements() // 忽略元素,只关注完成信号
            .andThen(
                Single.fromCallable {
                    appPreference.clearAllFeedback()
                    REMOTE_SAVED
                }
            )
            .onErrorReturn {
                // 处理错误,比如返回本地保存标记或自定义错误信息
                LOCAL_SAVED
            }
    } else {
        Single.just(LOCAL_SAVED)
    }
}

关键说明

  • concatMapSingle:保证Observable序列中的每个任务按顺序执行,前一个任务完成后才会启动下一个,彻底解决原代码异步并行导致的顺序混乱问题。
  • toList():收集所有图片上传后的URL,确保所有图片上传完成后才调用uploadDataToFirebaseFeedbackDocument,避免listOfImagePath为空的情况。
  • 错误处理:通过onErrorReturn捕获整个流程中的异常,可根据需求调整错误后的行为(比如回退到本地保存)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 03:05:16