WorkManager 退避延迟在某些设备上不起作用

WorkManager backoff delay doesn't work on some devices

我想启动一个 Worker 来执行一些任务,如果出现错误,在使用指数退避策略延迟一段时间后再次尝试。

为简洁起见,这里进行了简化Worker

class TestWorker(
    context: Context,
    workerParameters: WorkerParameters
) : Worker(
    context,
    workerParameters
) {
    override fun doWork(): Result {
        Log.d("DEBUG", "Attempt $runAttemptCount")
        return Result.retry()
    }
}

我就是这样安排的 Worker:

class MainActivity : AppCompatActivity() {

private val TAG = "WORKER_TAG"
private val BACKOFF_DELAY_SECONDS = 60L

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val workManager = WorkManager.getInstance()
        workManager.cancelAllWork()
        val workRequest = OneTimeWorkRequest.Builder(TestWorker::class.java)
            .setConstraints(
                Constraints
                    .Builder()
                    .setRequiredNetworkType(NetworkType.CONNECTED)
                    .build()
            )
            .setBackoffCriteria(
                BackoffPolicy.EXPONENTIAL,
                BACKOFF_DELAY_SECONDS,
                TimeUnit.SECONDS
            )
            .addTag(TAG)
            .build()

        workManager.enqueue(workRequest)
    }
}

它在大多数设备上运行良好,但我发现在某些设备上有奇怪的行为。

我希望尝试 2 在 1 分钟后执行,但在 Samsung J1 6.0.1 上我看到以下日志:

01-15 12:39:57.438 28396-28435/test.ru.workerissue D/DEBUG: Attempt 0
01-15 12:39:58.349 28396-28439/test.ru.workerissue D/DEBUG: Attempt 1
01-15 12:39:58.389 28396-28440/test.ru.workerissue D/DEBUG: Attempt 2
01-15 12:40:59.669 28396-28435/test.ru.workerissue D/DEBUG: Attempt 3
01-15 12:40:59.719 28396-28439/test.ru.workerissue D/DEBUG: Attempt 4

如您所见,除了 2 和 3 之外,所有尝试之间的延迟大约为 1 秒。

如果我 运行 在 Nexus 6X、8.1 上使用相同的代码,我观察到在启动时同时触发了两次尝试,然后一切都按预期工作:

2019-01-15 13:01:06.610 28806-28841/test.ru.workerissue D/DEBUG: Attempt 0
2019-01-15 13:01:06.658 28806-28842/test.ru.workerissue D/DEBUG: Attempt 1
2019-01-15 13:02:06.747 28806-28975/test.ru.workerissue D/DEBUG: Attempt 2
2019-01-15 13:04:06.876 28806-29024/test.ru.workerissue D/DEBUG: Attempt 3

另外,我在其他几台设备上对此进行了测试:Samsung Galaxy J3 - 8.0、Google Pixel XL - 8.1、Samsung Galaxy J1 - 5.1.1。在所有这些设备上都按预期工作。

WorkManager的版本是1.0.0-beta01

这种不一致的原因可能是什么?可以修复吗?

编辑: WorkManager 1.0.0-beta02 has been released with a fix for a bug that seems related to the problem you've

Fixed an edge case where periodic work could run more than once per interval on devices running Android 6.0 (API level 23).

原答案:
您应该尽量避免在每次应用程序启动时都将 WorkRequest 入队。 WorkManager 负责为您恢复工作,您不需要这样做。 有关 WorkManager 及其功能的更多信息,您应该查看解释此内容的 this blog series. There's also the video from Android Developer Summit talk "Working with WorkManager"

如果您需要在每次启动应用程序时将新作品入队,我建议您使用 REPLACE 政策将其作为唯一工作人员入队:

private val TAG = "WORKER_TAG"
private val BACKOFF_DELAY_SECONDS = 60L

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val workManager = WorkManager.getInstance()
        val workRequest = OneTimeWorkRequest.Builder(TestWorker::class.java)
            .setConstraints(
                Constraints
                    .Builder()
                    .setRequiredNetworkType(NetworkType.CONNECTED)
                    .build()
            )
            .setBackoffCriteria(
                BackoffPolicy.EXPONENTIAL,
                BACKOFF_DELAY_SECONDS,
                TimeUnit.SECONDS
            )
            .addTag(TAG)
            .build()

        // The first parameter is a unique string that identifies the work, I'm using the TAG here.
        workManager.enqueueUniqueWork(TAG, ExistingWorkPolicy.REPLACE, workRequest)
    }
}

我看到您正在使用 cancelAllWork() 方法。这是一种危险的方法,当它处于 运行(例如调用 isStopped)时,您没有采取任何行动来停止您的工作人员。

这可能是您在 nexus 设备上获得的额外日志的来源。

这个问题是我造成的,应该会在 WorkManager 的下一个版本中解决:https://issuetracker.google.com/issues/122881597