1

我有一个 android 应用程序需要在后台执行一些长时间运行的图像处理(处理它的很多块)

  • 我使用 WorkManager 来执行任务
  • 我使用用户通知来通知进度

版本

  • API 级别 28
  • 手机跑奥利奥
  • androidx.work:work-runtime:2.1.0

WorkManager 设置如下(简化代码)

@NonNull
@Override
public Result doWork() {
    // 1 Create a NotificationChannel with unique ID
    // 2 read params from getInputData
    // 3 create as many instances of a class 
    //     that extends Callable<String> as there are small subtasks
    // 4 add all these tasks to a ThreadPoolExecutor and call
    //     invokeAll() which blocks the main Worker thread as required
    //     by the WorkManager API
    // 5 Everytime a subtask finishes, update the notification progress
}

@Override
public void onStopped(){
    // Call .shutDown() on the ThreadPoolExecutor
}

作品本身使用以下参数提交

WorkManager mWorkManager = WorkManager.getInstance(context);
Data input = new Data.Builder()
                 .putString(PARAM_IN_DTO, dto.toString())
                 .build();
OneTimeWorkRequest mRequest = new OneTimeWorkRequest
                 .Builder(ExtractorWorker.class)
                 .setInputData(input)
                 .addTag(dto.mapName)
                 .build();
mWorkManager.enqueueUniqueWork(
                 WORK_NAME,
                 ExistingWorkPolicy.KEEP,
                 mRequest);

正如WORK_NAME上面的代码所独有的,我希望永远不会有两个任务同时运行(注意我尝试过ExistingWorkPolicy.REPLACE- 相同的问题)

作业正确启动,通知中的进度开始更新。过了一会儿,任务似乎又开始了,而前一个任务仍在运行。我从在两个状态之间切换的唯一通知中看到了这一点(通知年龄now和上一个年龄之间的时间,以及 0% 和上一个进度之间的进度)。现在显然有两个任务会更新相同的通知。我通过设置一个随机通知 ID 而不是唯一的 ID 来确认这一点,然后出现了两个通知,每个通知都过着自己的生活。

我想知道

  • 为什么 WorkManager 会在前一个任务仍在运行并且我没有从应用程序请求任何内容时再次提交此任务
  • 如果我只提交一个,怎么可能同时运行两个作业enqueueUniqueWork
4

2 回答 2

1

“长时间运行的图像处理”需要多长时间?

WorkManager 对其工作人员有 10 分钟的硬限制(与底层 JobScheduler API 的限制相同)。如果一个 Worker 耗时超过 10 分钟,它会被取消并重新调度,在这种情况下,Worker 返回的任何内容都会被 WorkManager 丢弃。工人将像以前从未执行过一样被执行。

如果您未能停止 Worker(isStopped()您的方法中还可以使用一个函数doWork()来检查这种情况),您最终可能会同时运行您的 Worker 的两个实例。

您可以在文档中找到更多信息

于 2019-08-10T15:34:13.337 回答
0

我想我现在确实理解这种行为。当WorkManager想要中断作业(稍后恢复)onStopped()时,会以非常短的超时时间调用。executor.shutDown()调用超过此值并抛出 a似乎TimeoutException导致关机无法正常执行。执行继续。

在引发此超时后,由于doWork没有按时返回任何内容,WorkManager 必须假定结果值为retryorfail并将作业重新发送到其内部执行程序。

简而言之,不能保证两个作业不会并行运行。如果一个作业在被调用时未能正确快速地停止onStopped,仍然会提交一个新作业。Workmanager 不会直接管理其执行程序中的线程,也不会中断在需要时未正确停止并可能重新启动它的作业。

在这种情况下,解决方案是让我将作业的内部状态设置为取消,以便它们在开始时立即完成。一旦执行程序用完,它就会删除一个锁定文件。新进程(恢复)在检查工作状态之前等待锁定文件消失并从那里恢复。

于 2019-08-10T12:51:04.267 回答