首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Android OkHttp/Retrofit如何在应用程序挂起到后台时继续多部分上传

Android OkHttp/Retrofit如何在应用程序挂起到后台时继续多部分上传
EN

Stack Overflow用户
提问于 2022-10-03 19:55:06
回答 1查看 120关注 0票数 0

我一直在为一个特定需求的应用程序的文件上传功能工作。上传端点被一系列多部分请求击中,并导致一个单一的“提交”。就当它是一批X文件。每个文件都需要一个进度指示符。文件被允许是大的,必须在缓慢的连接上上传,因此它们是连续上传的。

假设应用程序在前景中保持活动状态,它的行为就像预期的那样。我的麻烦是处理一系列的文件上传时,应用程序被放在后台。到目前为止,基于日志记录,上传将暂停,直到应用程序恢复。进程中的某些内容还会导致重试,在某些情况下,根据应用程序挂起和恢复的次数,该文件会上传多次。

处理这件事的最好方法是什么?

Service.kt

代码语言:javascript
复制
@Multipart
@POST("upload/files")
suspend fun uploadFilesWithName(@Header("finalFile") finalFile: Boolean,
                                @Part file: MultipartBody.Part) : Response<FileUploadResponse>

Repository.kt

代码语言:javascript
复制
fun uploadFilesWithComplete(files: MutableList<MultipartBody.Part>): LiveData<ApiState<FileUploadResponse>?> = liveData {

    val counter = AtomicInteger()

    files.forEachIndexed { index, file ->

        submitFilesWithName(finalFile = (files.size - 1 == index), file = file)

            .onStart { emit(ApiState.loading()) }
            .collect { response ->
                counter.incrementAndGet()

                when(response) {
                    is ApiSuccessResponse<FileUploadResponse> -> {
                        emit(ApiState.success(data = response.data, position = index))
                    }

                    is ApiErrorResponse<FileUploadResponse> -> {
                        if (response.error != null) {
                            emit(
                                ApiState.error(
                                    error = response.error,
                                    msg = response.error.validation.summary,
                                    position = index
                                )
                            )
                        } else {
                            emit(
                                ApiState.error(
                                    error = null,
                                    msg = "Error uploading file.",
                                    position = index
                                )
                            )
                        }
                    }
                    else -> {}
                }
            }
    }
}

suspend fun submitFilesWithName(finalFile: Boolean = false,
                                file: MultipartBody.Part
) : Flow<ApiResponse<FileUploadResponse>?> {
    return flow {
        emit (
            ApiResponse.make(
                requestFunc = { service.uploadFilesWithName(
                    finalFile = finalFile,
                    file = file
                )},
                maxRetries = SHORT_RETRY_ATTEMPTS
            )
        )
    }.flowOn(Dispatchers.IO)
}

FileUploadDialog.kt

代码语言:javascript
复制
val files: MutableList<MultipartBody.Part>
... // Add files to the multipart body list
repository?.uploadFilesWithComplete(files = files)?.observe(viewLifecycleOwner) { response ->
    if (response != null) {
        when (response.status) {
            Status.LOADING -> { /* kick off a loading animation */ }
            Status.SUCCESS -> {
                response.position?.let { position ->
                    selectedFiles.value?.let { selected ->
                        selected[position].apply {
                            inError = false
                            errorMessage = ""
                            isComplete = true
                        }
                        binding.fileList.adapter?.notifyItemChanged(position)
                    }
                }
            }
            Status.ERROR -> {
                response.position?.let { position ->
                    selectedFiles.value?.let { selected ->
                        selected[position].apply {
                            inError = true
                            errorMessage = "Upload Failed"
                            isComplete = true
                        }
                        binding.fileList.adapter?.notifyItemChanged(position)
                    }
                }
            }
        }
    }
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-10-03 20:07:43

谷歌建议在这种情况下使用Work Manager。从你说的可以被认为是Long-running work

https://developer.android.com/guide/background

另一种选择是使用Services,但这不应该是您的第一个选择。

Android 12限制从后台启动前台服务。在大多数情况下,您应该从WorkManager中使用WorkManager(),而不是自己处理前台服务。这允许WorkManager管理放弃服务的生命周期,从而确保效率。

您仍然应该使用前台服务来执行长期运行的任务,并且需要通知用户它们正在进行中。如果直接使用前台服务,请确保正确关闭服务以保持资源效率。

此外,也有多个图书馆帮助这些东西,但作为任何第三方图书馆,发展是不确定的,并不总是最新的。

示例:https://github.com/gotev/android-upload-service

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73940234

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档