将初始延迟设置为Android中的Periodic Work Manager

Sri*_*m R 10 android kotlin android-workmanager

我有一个Worker需要每24小时运行一次的实例,考虑到PeriodicWorkRequestAPI ,这很简单.但这是抓住了.

如果用户在下午8点开始工作,我需要工作管理器的第一个实例在第二天早上9点运行,然后遵循24小时定期约束.

我看了一下这里,我发现OneTimeWorkRequest API有一个setInitialDelay()可以使用的功能,但我无法找到任何PeriodicWorkAPI.

这是一些hacks,例如我可以使用OneTimeWork初始延迟,然后PeriodicWork从那里安排一个但是它有点肮脏的黑客.

有没有办法只用PeriodicWorkRequestAPI 来做到这一点?

Anj*_*een 11

在新版本的工作管理器(2019 年 5 月 16 日发布的版本 2.1.0-alpha02)上,PeriodicWorkRequests 现在支持初始延迟。您可以使用 PeriodicWorkRequest.Builder 上的 setInitialDelay 方法来设置初始延迟。

例子:

    PeriodicWorkRequest workRequest = new PeriodicWorkRequest.Builder(
        WorkerReminderPeriodic.class,
        24,
        TimeUnit.HOURS,
        PeriodicWorkRequest.MIN_PERIODIC_FLEX_MILLIS,
        TimeUnit.MILLISECONDS)
      .setInitialDelay(1, TimeUnit.HOURS)
      .addTag("send_reminder_periodic")
      .build();


    WorkManager.getInstance()
        .enqueueUniquePeriodicWork("send_reminder_periodic", ExistingPeriodicWorkPolicy.REPLACE, workRequest);
Run Code Online (Sandbox Code Playgroud)

  • `setInitialDelay` 工作起来很奇怪。当我设置启动时间为 15 分钟,初始延迟为 1 分钟时,工作线程将在 16 分钟后启动。我认为它会立即(如“OneTimeWorkRequest”),但在 1 分钟后(而不是在 16 分钟后)。随后每 15 分钟启动一次。 (3认同)
  • @proninyaroslav 定期工作的最小间隔为 15 分钟,并且不能有初始延迟。MIN_PERIODIC_INTERVAL_MILLIS 为 15 分钟。https://developer.android.com/reference/kotlin/androidx/work/PeriodicWorkRequest#min_periodic_interval_millis (2认同)
  • 无法在PeriodicWorker上设置初始延迟,初始延迟仅适用于oneTimeWorker (2认同)
  • 我正在使用版本“implementation 'android.arch.work:work-runtime:1.0.1'”,这里不存在 setInitialDelay() 。抱歉,我使用的是“WorkManager”的稳定版本,而不是 alpha。 (2认同)

Raf*_*gas 6

PeriodicWorkRequest有一个很好的 Builder 构造函数,您可以在其中传递工作可以执行的间隔。您可以在此处查看Builder 和每个参数的详细信息

因此,要为您的定期工作设置初始延迟,您可以这样做:

int hourOfTheDay = 10; // When to run the job
int repeatInterval = 1; // In days

long flexTime = calculateFlex(hourOfTheDay, repeatInterval);

Constraints myConstraints = new Constraints.Builder()
        .setRequiresBatteryNotLow(true)
        .build();

PeriodicWorkRequest workRequest =
        new PeriodicWorkRequest.Builder(MyNiceWorker.class,
                repeatInterval, TimeUnit.DAYS,
                flexTime, TimeUnit.MILLISECONDS)
                .setConstraints(myConstraints)
                .build();

WorkManager.getInstance().enqueueUniquePeriodicWork(YOUR_NICE_WORK_TAG,
        ExistingPeriodicWorkPolicy.REPLACE,
        workRequest);
Run Code Online (Sandbox Code Playgroud)

这是魔法发生的地方:

private long calculateFlex(int hourOfTheDay, int periodInDays) {

    // Initialize the calendar with today and the preferred time to run the job.
    Calendar cal1 = Calendar.getInstance();
    cal1.set(Calendar.HOUR_OF_DAY, hourOfTheDay);
    cal1.set(Calendar.MINUTE, 0);
    cal1.set(Calendar.SECOND, 0);

    // Initialize a calendar with now.
    Calendar cal2 = Calendar.getInstance();

    if (cal2.getTimeInMillis() < cal1.getTimeInMillis()) {
        // Add the worker periodicity.
        cal2.setTimeInMillis(cal2.getTimeInMillis() + TimeUnit.DAYS.toMillis(periodInDays));
    }

    long delta = (cal2.getTimeInMillis() - cal1.getTimeInMillis());

    return ((delta > PeriodicWorkRequest.MIN_PERIODIC_FLEX_MILLIS) ? delta
            : PeriodicWorkRequest.MIN_PERIODIC_FLEX_MILLIS);
}
Run Code Online (Sandbox Code Playgroud)

请注意,这个时间并不准确。WorkManager可能会在该弹性窗口中随时触发您的作业,具体取决于您的约束、系统负载、其他计划作业等。

如果您想要精确的计时,请切换到AlarmManager

希望能帮助到你!


Qas*_*sim 4

对于当前的 alpha 版本WorkManager( v1.0.0-alpha07),我认为不可能为PeriodicWorkReqeust. 也许我们会在下一个版本中获得一些 API。

目前,正如您所说,您可以使用OneTimeWork具有初始延迟的请求设置,然后将请求排队PeriodicWork到 WorkManager。

我想说这是一种黑客行为,但并没有那么肮脏。