android - Android - WorkManager - Result.success() 调用次数过多
问题描述
我的应用程序出现问题。我正在尝试将一些照片上传到云中,然后,我将向用户显示要复制的 url 列表,以便第二次使用它们。
我正在为此使用 RxWorker。
当我将工人列表排入队列时,一切似乎都很好(每个图像一个 OneTimeWorkRequestBuilder),但是当我检索结果时,似乎我的观察被触发了太多次。
为了使此步骤可暂停,我有两个列表(图像和工作人员)。当一项工作完成时(无论是失败还是成功),我都会从他们自己的列表中取消图像和工作人员。
这是我的代码。谢谢大家!
我的片段:
class ImagesUploadFragment : Fragment() {
companion object {
private const val TAG = "ImagesUploadFragment"
private const val PHOTOS_LIST = "PHOTOS_LIST"
private const val WORK_NAME = "PHOTO_UPLOAD"
fun newInstance(optionalData: String?): ImagesUploadFragment {
val imagesUploadFragment = ImagesUploadFragment()
val bundle = Bundle()
bundle.putString(PHOTOS_LIST, optionalData)
imagesUploadFragment.arguments = bundle
return imagesUploadFragment
}
}
private lateinit var imagesUploadBinding: FragmentImagesUploadBinding
private var stepListener: StepListener? = null
private val mDownloadUrlsList = mutableListOf<String>()
private val mWorkManger: WorkManager by lazy { WorkManager.getInstance(requireContext()) }
private val mWorkRequestList = mutableListOf<OneTimeWorkRequest>()
private var isUploadPaused = false
private val mImagesList = mutableListOf<String>()
private val gson: Gson by inject()
override fun onAttach(context: Context) {
super.onAttach(context)
stepListener = context as? StepListener
}
private val imagesUploadViewModel: ImagesUploadViewModel by viewModel()
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
imagesUploadBinding = FragmentImagesUploadBinding.inflate(inflater, container, false)
return imagesUploadBinding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val imagesList = arguments?.getString(PHOTOS_LIST)
imagesList?.let {
startImagesUpload(it)
}
imagesUploadBinding.successfullyUpdated.text = String.format(getString(R.string.succeeded_updates), 0)
imagesUploadBinding.workActionIv.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.ic_pause))
imagesUploadBinding.buttonContinue.setOnClickListener {
stepListener?.onStepChange(4, gson.toJson(mDownloadUrlsList))
}
mWorkManger.cancelAllWorkByTag(TAG)
mWorkManger.cancelAllWork()
mWorkManger.pruneWork()
imagesUploadBinding.workActionIv.setOnClickListener {
if (!isUploadPaused) {
isUploadPaused = true
pauseUpload()
imagesUploadBinding.workActionIv.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.ic_play))
} else {
isUploadPaused = false
resumeUpload()
imagesUploadBinding.workActionIv.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.ic_pause))
}
}
setupWorkManagerObserve()
with(imagesUploadViewModel) {
observe(imagesListResource,
success = { imagesList ->
imagesUploadBinding.uploadProgress.max = imagesList.first.size
mImagesList.addAll(imagesList.first.map { it.jsonValue })
setupWorkerList()
},
failure = {
Timber.e(it)
}
)
observe(uploadedFileResource,
success = {
if(it.isNotEmpty()) mDownloadUrlsList.add(it)
imagesUploadBinding.buttonContinue.isVisible = mImagesList.size == 0
imagesUploadBinding.workActionIv.isVisible = mImagesList.size > 0
imagesUploadBinding.horizontalSpace.isVisible = mImagesList.size > 0
},
failure = {
Timber.e(it)
}
)
}
}
private fun pauseUpload() {
mWorkManger.cancelAllWork()
}
private fun resumeUpload() {
setupWorkerList()
}
private fun startImagesUpload(imagesListJson: String) {
imagesUploadViewModel.getImagesFromUri(imagesListJson)
}
private fun setupWorkManagerObserve() {
mWorkManger
.getWorkInfosByTagLiveData(TAG)
.observe(viewLifecycleOwner) {
var successNumber = 0
var failureNumber = 0
it.forEach { work ->
when {
work.state == WorkInfo.State.SUCCEEDED && work.state.isFinished -> {
successNumber++
val image = work.outputData.getString(PHOTO)
val uploadedFileJson = work.outputData.getString(UPLOAD_RESPONSE)
mWorkRequestList.removeAll { it.id == work.id }
mImagesList.removeAll { it == image }
uploadedFileJson?.let {
imagesUploadViewModel.getDownloadUrlFromResponse(it)
}
imagesUploadBinding.uploadProgress.progress = successNumber + failureNumber
imagesUploadBinding.successfullyUpdated.text =
String.format(getString(R.string.succeeded_updates), successNumber)
}
work.state == WorkInfo.State.RUNNING -> {
}
work.state == WorkInfo.State.FAILED -> {
failureNumber++
val image = work.outputData.getString(PHOTO)
mWorkRequestList.removeAll { it.id == work.id }
mImagesList.removeAll { it == image }
imagesUploadBinding.uploadProgress.progress = successNumber + failureNumber
imagesUploadBinding.failuredUpdated.text =
String.format(getString(R.string.failed_updates), failureNumber)
imagesUploadViewModel.addFailure()
}
else -> {
}
}
}
}
}
private fun setupWorkerList() {
for (i in 0 until mImagesList.size) {
val work = OneTimeWorkRequestBuilder<ImagesUploadWorkManager>()
.addTag(TAG)
.setInputData(Data.Builder().putString(PHOTO, mImagesList[i])
.build())
.build()
mWorkRequestList.add(work)
}
mWorkManger.enqueue(mWorkRequestList)
}
}
我的工人:
class ImagesUploadWorkManager(val context: Context, parameters: WorkerParameters) : RxWorker(context, parameters) {
companion object {
const val PHOTO = "PHOTO"
const val UPLOAD_RESPONSE = "UPLOAD_RESPONSE"
}
private val uploadFilesUseCase: UploadFilesUseCase by inject(UploadFilesUseCase::class.java)
private val gson: Gson by inject(Gson::class.java)
override fun createWork(): Single<Result> {
val imageStringUri = inputData.getString(PHOTO)
val imageUri = Uri.parse(imageStringUri)
return Single.fromObservable(
uploadFilesUseCase.buildObservable(UploadFilesUseCase.Params(imageUri))
.doOnError {
Timber.e(it)
}
.map {
Result.success(workDataOf(UPLOAD_RESPONSE to gson.toJson(it), PHOTO to imageStringUri))
}
.onErrorReturn {
Timber.e(it)
Result.failure(workDataOf(PHOTO to imageStringUri))
}
)
}
}
我的用例:
class UploadFilesUseCase(
private val context: Context,
private val getServerUseCase: GetServerUseCase,
) : UseCase<UploadFilesUseCase.Params, GoFileDataEntity>() {
private val goFileApi: GoFileApi by inject(GoFileApi::class.java)
override fun buildObservable(param: Params): Observable<GoFileDataEntity> {
return Observable.just(param.imageUri)
.flatMap {
val file = createTempFile(it) ?: throw Exception()
Observable.just(file)
}.flatMap { imageFile ->
getServerUseCase.buildObservable(GetServerUseCase.Params())
.flatMap { server ->
goFileApi.uploadFile(
String.format(BuildConfig.api_gofile_upload, server.server),
MultipartBody.Part.createFormData("file", imageFile.name, createUploadRequestBody(imageFile, "image/jpeg"))
).toObservable()
}.map { it.goFileDataDTO.toEntity() }
}
}
private fun createUploadRequestBody(file: File, mimeType: String) =
file.asRequestBody(mimeType.toMediaType())
private fun createTempFile(uri: Uri): File? {
val tempFile = File.createTempFile(System.currentTimeMillis().toString().take(4), ".jpg", context.externalCacheDir)
val inputStream = context.contentResolver.openInputStream(uri) ?: return null
FileOutputStream(tempFile, false).use { outputStream ->
var read: Int
val bytes = ByteArray(DEFAULT_BUFFER_SIZE)
while (inputStream.read(bytes).also { read = it } != -1) {
outputStream.write(bytes, 0, read)
}
outputStream.close()
}
inputStream.close()
return tempFile
}
data class Params(val imageUri: Uri)
}
解决方案
我有一个类似的问题,看起来队列已经从以前的 Workmanager 排队中满了。
我在应用程序启动期间做了以下操作,现在它工作正常:
WorkManager.getInstance(mContext).cancelAllWork();
推荐阅读
- angular - (更改)仅在角 2 中按 enter 后才能工作
- django - django manytomany访问相关列
- sql - 如果没有明确指定,liquibase 如何选择模式?
- ocaml - 如何将模块映射到 OCaml 中的模块类型?
- c# - 如果先前的操作超时,EF SqlQuery 将抛出不支持的 MultipleActiveResultSets 异常
- javascript - 即时修改 .serialize() 的结果
- selenium - Selenium 和 Firefox 的可重现截图
- c# - 计算总和 - Datagridview 的 CellFormating 事件性能太慢
- jquery-select2 - Select2 刷新丢失所有类?更改单个选项文本
- elasticsearch - 发现 Elasticsearch 的历史趋势(非可视化)