我一直在为一个特定需求的应用程序的文件上传功能工作。上传端点被一系列多部分请求击中,并导致一个单一的“提交”。就当它是一批X文件。每个文件都需要一个进度指示符。文件被允许是大的,必须在缓慢的连接上上传,因此它们是连续上传的。
假设应用程序在前景中保持活动状态,它的行为就像预期的那样。我的麻烦是处理一系列的文件上传时,应用程序被放在后台。到目前为止,基于日志记录,上传将暂停,直到应用程序恢复。进程中的某些内容还会导致重试,在某些情况下,根据应用程序挂起和恢复的次数,该文件会上传多次。
处理这件事的最好方法是什么?
Service.kt
@Multipart
@POST("upload/files")
suspend fun uploadFilesWithName(@Header("finalFile") finalFile: Boolean,
@Part file: MultipartBody.Part) : Response<FileUploadResponse>Repository.kt
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
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)
}
}
}
}
}
}发布于 2022-10-03 20:07:43
谷歌建议在这种情况下使用Work Manager。从你说的可以被认为是Long-running work。
https://developer.android.com/guide/background
另一种选择是使用Services,但这不应该是您的第一个选择。
Android 12限制从后台启动前台服务。在大多数情况下,您应该从WorkManager中使用WorkManager(),而不是自己处理前台服务。这允许WorkManager管理放弃服务的生命周期,从而确保效率。
您仍然应该使用前台服务来执行长期运行的任务,并且需要通知用户它们正在进行中。如果直接使用前台服务,请确保正确关闭服务以保持资源效率。
此外,也有多个图书馆帮助这些东西,但作为任何第三方图书馆,发展是不确定的,并不总是最新的。
https://stackoverflow.com/questions/73940234
复制相似问题