Установите начальную задержку для Periodic Work Manager в Android

У меня есть Worker экземпляр, который нужно запускать каждые 24 часа, что довольно просто, учитывая PeriodicWorkRequest API. Но вот в чем загвоздка.

Если пользователь начинает работу, скажем, в 8 часов вечера, мне нужно, чтобы первый экземпляр диспетчера работ запускался в 9 часов утра следующего дня, а затем следовал 24-часовому периодическому ограничению.

Я посмотрел здесь и обнаружил, что В OneTimeWorkRequest API есть setInitialDelay() функция, которую можно использовать, но мне не удалось найти ничего для PeriodicWork API.

Для этого есть несколько приемов, например, я могу использовать OneTimeWork с начальной задержкой, а затем запланировать PeriodicWork оттуда, но это своего рода грязный прием.

Есть ли способ сделать это только с помощью PeriodicWorkRequest API?


person Sriram R    schedule 21.08.2018    source источник


Ответы (3)


В новой версии Диспетчера работ (Версия 2.1.0-alpha02 выпущено 16 мая 2019 г.) PeriodicWorkRequests теперь поддерживает начальные задержки. Вы можете использовать метод setInitialDelay в PeriodicWorkRequest.Builder, чтобы установить начальную задержку.

Пример:

    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);
person Anjal Saneen    schedule 22.05.2019
comment
setInitialDelay работает странно. Когда я устанавливаю период запуска 15 минут и начальную задержку 1 минуту, рабочий запускается через 16 минут. Думал сразу (как OneTimeWorkRequest), но через 1 минуту (а не через 16 минут). И последующие запуски будут каждые 15 минут. - person proninyaroslav; 23.07.2019
comment
@proninyaroslav Периодическая работа имеет минимальный интервал 15 минут и не может иметь начальной задержки. MIN_PERIODIC_INTERVAL_MILLIS - 15 минут. developer.android.com/reference/kotlin/androidx/work/ - person Anjal Saneen; 23.07.2019
comment
Спасибо. Я попробую проделать трюк с OneTimeWorkRequest - person proninyaroslav; 24.07.2019
comment
Начальная задержка не может быть установлена ​​на PeriodicWorker, начальная задержка только для oneTimeWorker - person SmartAndroidian; 01.08.2019
comment
@SmartAndroidian Можете проверить версию Диспетчера работ? это должна быть версия 2.1.0-alpha02 +, чтобы получить setInitialDelay (). - person Anjal Saneen; 03.08.2019
comment
Я использую версию implementation 'android.arch.work:work-runtime:1.0.1', а здесь нет setInitialDelay (). Извините, я использую стабильную версию WorkManager, а не альфа-версию. - person SmartAndroidian; 05.08.2019
comment
@SmartAndroidian Вы можете использовать стабильную версию 2.2.0-rc01. это тоже там. - person Anjal Saneen; 05.08.2019
comment
Небольшое уточнение, этот метод (setInitialDelay) не работает у воркера на android 23, версия worker 2.4.0 - person Evgeny Gil; 08.11.2020

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);

Вот где происходит волшебство:

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);
}

Имейте в виду, что это время неточно. WorkManager может запускать ваше задание в любое время в этом гибком окне в зависимости от ваших ограничений, загрузки системы, других запланированных заданий и т. д.

Если вам нужно точное время, переключитесь на AlarmManager.

Надеюсь, поможет!

person Rafael Chagas    schedule 28.01.2019
comment
Документы говорят, что flexTime игнорируется в определенных версиях API (например, 23) ... Есть ли еще какое-нибудь разумное решение? - person Michał Powłoka; 06.04.2019

В текущей альфа-версии WorkManager (v1.0.0-alpha07) я думаю, что невозможно установить начальную задержку для PeriodicWorkReqeust. Возможно, в следующих выпусках мы получим какой-нибудь API.

Пока, как вы сказали, вы можете использовать OneTimeWork настройку запроса с начальной задержкой, которая затем поставит PeriodicWork запрос в WorkManager в очередь.

Я бы сказал, что это взлом, но не такой уж грязный.

person Qasim    schedule 21.08.2018
comment
Да, это моя текущая стратегия. Мне просто интересно, есть ли какой-нибудь простой способ. - person Sriram R; 21.08.2018
comment
@qasim, есть коды, как этого добиться? - person Noor Hossain; 30.12.2020