【问题标题】:Android WorkManager resending unique task while it is runningAndroid WorkManager 在运行时重新发送唯一任务
【发布时间】:2019-08-10 09:13:21
【问题描述】:

我有一个 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 提交一个作业,怎么会有两个作业同时运行?

【问题讨论】:

    标签: android android-workmanager android-threading


    【解决方案1】:

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

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

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

    You can find more on the documentation

    【讨论】:

      【解决方案2】:

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

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

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-10-29
        • 1970-01-01
        • 1970-01-01
        • 2020-01-31
        • 1970-01-01
        • 2014-09-28
        相关资源
        最近更新 更多