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

Kotlin中如何串行调用带回调的uploadVideo方法?

问题

我有一个从服务器返回响应的uploadVideo方法,定义如下:

fun uploadVideo(link: String, completionHandler: (Result<String>) -> Unit) {
    // some action
    completionHandler(Result.success(""))
}

我希望逐个调用该方法,必须等待前一个请求的响应返回后,再调用下一个,示例场景如下:

uploadVideo("https://stackoverflow.com/video1.mp4") {
  
}

// 仅在前一个请求响应返回后再调用
uploadVideo("https://stackoverflow.com/video2.mp4") {
  
}

// 仅在前一个请求响应返回后再调用
uploadVideo("https://stackoverflow.com/video3.mp4") {
  
}

我尝试用suspendCancellableCoroutine将其封装为挂起函数:

suspend fun uploadVideo(link: String?): String? = suspendCancellableCoroutine { cont ->
        uri?.let {
            uploadVideo(link,
                completionHandler = {
                    it.onSuccess { uri ->
                        cont.resume(uri.toString())
                    }.onFailure {
                        cont.resumeWithException(it)
                    }
                }
            )
        } ?: kotlin.run {
            cont.resume(null)
        }
    }

并按如下方式调用:

uploadVideo("https://stackoverflow.com/video1.mp4")
uploadVideo("https://stackoverflow.com/video2.mp4")
uploadVideo("https://stackoverflow.com/video3.mp4")

但这些方法并未串行执行,而是并行执行了,请问该如何解决?

解决方案

你的挂起函数封装逻辑没问题,但调用方式有误——挂起函数本身不会自动保证串行,必须在同一个协程内按顺序调用,利用挂起函数会暂停协程的特性,等待前一个请求完成后再执行下一行代码。

步骤1:修正挂起函数封装(修复变量未定义问题)

原封装代码里的uri是未定义变量,调整为正确的版本:

suspend fun uploadVideoSuspend(link: String): String = suspendCancellableCoroutine { cont ->
    uploadVideo(link) { result ->
        result.onSuccess { cont.resume(it) }
            .onFailure { cont.resumeWithException(it) }
    }
}

如果需要支持link为null的场景,可保留返回String?的逻辑,确保变量引用正确即可。

步骤2:在协程内顺序调用

将所有上传调用放在同一个协程作用域(比如viewModelScope、LifecycleScope)内,按顺序编写代码,挂起函数会自动暂停协程,直到当前请求完成后再执行下一个:

// 在协程作用域内执行
viewModelScope.launch {
    try {
        // 第一个上传完成后才会执行第二个
        val result1 = uploadVideoSuspend("https://stackoverflow.com/video1.mp4")
        // 第二个上传完成后才会执行第三个
        val result2 = uploadVideoSuspend("https://stackoverflow.com/video2.mp4")
        val result3 = uploadVideoSuspend("https://stackoverflow.com/video3.mp4")
        // 所有上传完成后的处理逻辑
    } catch (e: Exception) {
        // 处理上传失败的异常
    }
}

步骤3:批量处理视频链接(可选)

如果有多个视频链接需要串行上传,用循环遍历更简洁:

viewModelScope.launch {
    val videoLinks = listOf(
        "https://stackoverflow.com/video1.mp4",
        "https://stackoverflow.com/video2.mp4",
        "https://stackoverflow.com/video3.mp4"
    )
    for (link in videoLinks) {
        try {
            val result = uploadVideoSuspend(link)
            // 单个视频上传成功的处理逻辑
        } catch (e: Exception) {
            // 可选:失败后中断后续上传,或继续执行
            break // 中断后续上传
            // continue // 忽略当前失败,继续上传下一个
        }
    }
}

为什么之前的调用会并行?

如果你的三次uploadVideo调用是在不同协程中执行(比如分别用launch启动),就会导致并行。只要确保所有调用都在同一个协程的代码块内,按顺序编写,就能保证串行执行。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 21:30:48