我正在使用 Retrofit2 在单个多部分请求中上传动态数量的文件。我的改造界面看起来像这样 -
public interface FileUploadService {
@Multipart
@POST("upload")
Call<ResponseBody> uploadMultipleFilesDynamic(
@Part List<MultipartBody.Part> files);
}
现在我想跟踪此多文件上传的进度。此解决方案说明了如何通过扩展RequestBody
在多部分请求中上传单个文件时获得进度。虽然我似乎无法理解如何将它应用于我的多个文件请求。我能想到的一个解决方案是通过扩展类而不是RequestBody
来创建ProgressRequestBody
OkHTTP MultipartBody
但OkHTTP3
实现MultipartBody
作为最终类,使其无法扩展。任何人都可以指出我正确的方向,因为无法向用户显示文件上传进度对我来说是一个巨大的障碍。或者我可以实施任何解决方法来实现此功能?
我关注了这篇博文: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)
}