【问题标题】:How to get progress for multipart multiple files upload using OkHTTP3/Retrofit2?如何使用 OkHTTP3/Retrofit2 获取多部分文件上传的进度?
【发布时间】:2017-12-14 14:59:02
【问题描述】:

我正在使用 Retrofit2 在单个多部分请求中上传动态数量的文件。我的改造界面是这样的——

public interface FileUploadService {  
    @Multipart
    @POST("upload")
    Call<ResponseBody> uploadMultipleFilesDynamic(
            @Part List<MultipartBody.Part> files);
}

现在我想跟踪这个多文件上传的进度。 This solution 解释了如何通过扩展 RequestBody 在多部分请求中上传单个文件时获得进度。尽管我似乎无法理解如何将其应用于我的多个文件请求。我能想到的一种解决方案是通过扩展OkHTTP MultipartBody 类而不是RequestBody 来创建ProgressRequestBody,但OkHTTP3 实现MultipartBody 作为最终类使其无法扩展。谁能指出我正确的方向,因为这对我来说是一个巨大的障碍,无法向用户显示文件上传的进度。或者我可以实施什么变通方法来实现此功能?

【问题讨论】:

  • 我需要相同的解决方案你找到了吗?
  • @KhizarHayat 您可以通过让 ProgressRequestBody 将部件号和进度侦听器作为参数来实现此目的。然后 ProgressRequestBody 可以调用进度侦听器,将部件号作为参数和传输的字节数传递。然后,监听器实现将通过考虑当前部件号、所有部件的大小和到目前为止传输的部件的大小,对多部分请求进行组合进度计算。
  • 感谢@shubam1g5 的回复。你能分享一些代码吗?
  • 你可以查看Link
  • 对于那些仍然坚持使用 Retrofit 1.x 的人,我们最终使用了一个简单、有效的解决方案:stackoverflow.com/a/24772058/293280

标签: android retrofit2 okhttp multipart


【解决方案1】:

我关注了这篇博文:https://medium.com/@PaulinaSadowska/display-progress-of-multipart-request-with-retrofit-and-rxjava-23a4a779e6ba,然后进行了以下调整以显示总进度而不是单独文件的进度:

  private fun prepareFileParts(reportAttachments: MutableList<ReportAttachment>, emitter: FlowableEmitter<Double>): List<MultipartBody.Part> {
    val multiPartBodyList = mutableListOf<MultipartBody.Part>()

    var offset = 0L
    var totalLength = 0L

    // calculate the total length of all files
    for (attachment in reportAttachments) {
        val file = File(attachment.filePath)
        totalLength += file.length()
    }

    // create requestbody for each file and calculate the progression offset
    for (attachment in reportAttachments) {
        val file = File(attachment.filePath)
        val mimeType = attachment.mimeType

        val countingRequestBody = createCountingRequestBody(file, mimeType, emitter, offset, totalLength)
        offset += file.length()

        val multipartBody = MultipartBody.Part.createFormData("file", file.name, countingRequestBody)
        multiPartBodyList.add(multipartBody)
    }

    return multiPartBodyList
}

private fun createCountingRequestBody(file: File, mimeType: String, emitter: FlowableEmitter<Double>, offset: Long, totalLength: Long): RequestBody {
    val requestBody = RequestBody.create(MediaType.parse(mimeType), file)
    return CountingRequestBody(requestBody, object : CountingRequestBody.Listener {
        override fun onRequestProgress(bytesWritten: Long, contentLength: Long) {
            val progress: Double = 1.0 * (offset + bytesWritten) / totalLength
            emitter.onNext(progress)
        }
    })
}

如果需要,您还可以创建一个拦截器并将其添加到您的OkHttpClient。默认情况下,这将跟踪所有传出的 API 调用。它看起来像这样:

class UploadProgressInterceptor(private val progressListener: CountingRequestBody.Listener) : Interceptor {

override fun intercept(chain: Interceptor.Chain): Response {
    val originalRequest = chain.request()

    if (originalRequest.body() == null) {
        return chain.proceed(originalRequest)
    }

    val requestBody = originalRequest.body()
    requestBody?.let {
        val progressRequest = originalRequest.newBuilder()
                .method(originalRequest.method(), CountingRequestBody(it, progressListener))
                .build()
        return chain.proceed(progressRequest)
    }
    return chain.proceed(originalRequest)
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-09-05
    • 1970-01-01
    • 2019-03-02
    • 1970-01-01
    • 2017-01-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多