В кратком руководстве рассказывается, как создать объект WorkRequest и добавить его в очередь.
В этом руководстве рассказывается, как определять и настраивать объекты WorkRequest для решения распространенных задач, например:
- Планируйте разовые и повторяющиеся задачи.
- Задайте ограничения для работы, например необходимость подключения к Wi-Fi или зарядки.
- Гарантировать минимальную задержку при выполнении работы
- Настройте стратегии повторных попыток и отсрочки
- Передайте входные данные для работы
- Группируйте связанные задачи с помощью тегов
Обзор
Работа определяется в WorkManager с помощью WorkRequest. Чтобы запланировать работу с помощью WorkManager, сначала нужно создать объект WorkRequest, а затем поставить его в очередь.
Kotlin
val myWorkRequest = ...
WorkManager.getInstance(myContext).enqueue(myWorkRequest)
Java
WorkRequest myWorkRequest = ...
WorkManager.getInstance(myContext).enqueue(myWorkRequest);
Объект WorkRequest содержит всю информацию, необходимую WorkManager для планирования и выполнения работы. Она включает ограничения, которые должны быть соблюдены для выполнения работы, информацию о планировании, такую как задержки или повторяющиеся интервалы, конфигурацию повторных попыток, и может включать входные данные, если ваша работа зависит от них.
WorkRequest – это абстрактный базовый класс. Для создания запроса можно использовать две производные реализации этого класса: OneTimeWorkRequest и PeriodicWorkRequest.
Как следует из названий, OneTimeWorkRequest подходит для планирования разовых задач, а PeriodicWorkRequest – для повторяющихся.
Как запланировать однократное выполнение задачи
Для базовой работы, не требующей дополнительной настройки, используйте статический метод from:
Kotlin
val myWorkRequest = OneTimeWorkRequest.from(MyWork::class.java)
Java
WorkRequest myWorkRequest = OneTimeWorkRequest.from(MyWork.class);
Для более сложных задач можно использовать конструктор:
Kotlin
val uploadWorkRequest: WorkRequest =
OneTimeWorkRequestBuilder<MyWork>()
// Additional configuration
.build()
Java
WorkRequest uploadWorkRequest =
new OneTimeWorkRequest.Builder(MyWork.class)
// Additional configuration
.build();
Как запланировать приоритетную задачу
В WorkManager 2.7.0 появилось понятие приоритетной задачи. Это позволяет WorkManager выполнять важную работу, предоставляя системе лучший контроль над доступом к ресурсам.
Приоритетные задачи имеют следующие характеристики:
- Важность. Приоритетные задачи подходят для важных для пользователя или инициированных им задач.
- Скорость. Приоритетные задачи лучше всего подходят для коротких задач, которые начинаются немедленно и завершаются в течение нескольких минут.
- Квоты. Системная квота, ограничивающая время выполнения в активном режиме, определяет, может ли быть запущена приоритетная задача.
- Управление питанием. Ограничения управления питанием, такие как режим энергосбережения и спящий режим, с меньшей вероятностью повлияют на приоритетные задачи.
- Задержка. Система немедленно выполняет приоритетную задачу, если это позволяет текущая рабочая нагрузка. Это означает, что такие задачи чувствительны к задержкам и их нельзя запланировать на более позднее время.
Примером приоритетной задачи может быть отправка сообщения или прикрепленного изображения в мессенджере. Аналогично, приложение, которое обрабатывает платеж или подписку, также может использовать приоритетную задачу. Это связано с тем, что такие задачи важны для пользователя, быстро выполняются в фоновом режиме, должны начинаться немедленно и продолжаться, даже если пользователь закрывает приложение.
Квоты
Прежде чем запустить приоритетную задачу, система должна выделить для нее время выполнения. Время выполнения ограничено. Каждому приложению выделяется квота на время выполнения. Когда приложение использует все время выполнения и достигнет выделенной квоты, вы не сможете выполнять приоритетные задачи, пока квота не обновится. Это позволяет Android более эффективно распределять ресурсы между приложениями.
Время выполнения, доступное приложению, зависит от группы режима ожидания и важности процесса.
Вы можете определить, что происходит, когда квота на выполнение не позволяет немедленно запустить приоритетную задачу. Подробности приведены в следующих фрагментах кода.
Выполнение приоритетных задач
Начиная с версии WorkManager 2.7, приложение может вызывать setExpedited(), чтобы объявить, что WorkRequest должна выполняться как можно быстрее с помощью приоритетной задачи. В следующем фрагменте кода показано, как использовать setExpedited():
Kotlin
val request = OneTimeWorkRequestBuilder<SyncWorker>()
<b>.setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)</b>
.build()
WorkManager.getInstance(context)
.enqueue(request)
Java
OneTimeWorkRequest request = new OneTimeWorkRequestBuilder<T>()
.setInputData(inputData)
<b>.setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)</b>
.build();
В этом примере мы инициализируем экземпляр OneTimeWorkRequest и вызываем для него метод setExpedited(). Запрос становится приоритетной задачей. Если квота позволяет, он сразу же начнет выполняться в фоновом режиме. Если квота исчерпана, параметр OutOfQuotaPolicy указывает, что запрос должен быть выполнен как обычная, неприоритетная задача.
Обратная совместимость и активные службы
Чтобы обеспечить обратную совместимость приоритетных задач, WorkManager может запускать активную службу на устройствах с версиями ОС, предшествующими Android 12. Активные службы могут показывать пользователю уведомления.
Методы getForegroundInfoAsync() и getForegroundInfo() в Worker позволяют WorkManager показывать уведомление, когда вы вызываете setExpedited() в версиях до Android 12.
Если вы хотите, чтобы задача выполнялась как приоритетная, в любом классе ListenableWorker необходимо реализовать метод getForegroundInfo.
Если приложение предназначено для Android 12 или более поздней версии, активные службы остаются доступными через соответствующий метод setForeground.
Сотрудник
Работники не знают, выполняют ли они срочную работу. Однако в некоторых версиях Android рабочие процессы могут показывать уведомление, когда WorkRequest выполняется в срочном режиме.
Для этого в WorkManager есть метод getForegroundInfoAsync(), который нужно реализовать, чтобы WorkManager мог показывать уведомление для запуска ForegroundService, когда это необходимо.
CoroutineWorker
Если вы используете CoroutineWorker, необходимо реализовать getForegroundInfo(). Затем вы передаете его setForeground() в doWork(). Это позволит создать уведомление в версиях Android до 12.
Пример:
class ExpeditedWorker(appContext: Context, workerParams: WorkerParameters):
CoroutineWorker(appContext, workerParams) {
override suspend fun getForegroundInfo(): ForegroundInfo {
return ForegroundInfo(
NOTIFICATION_ID, createNotification()
)
}
override suspend fun doWork(): Result {
TODO()
}
private fun createNotification() : Notification {
TODO()
}
}
Правила в отношении квот
Вы можете указать, что должно происходить с приоритетными задачами, когда приложение достигает квоты на выполнение. Чтобы продолжить, вы можете передать setExpedited():
OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST, в результате чего задание выполняется как обычный запрос на работу. Это показано в приведенном выше фрагменте кода.OutOfQuotaPolicy.DROP_WORK_REQUEST, что приводит к отмене запроса, если квота недостаточна.
Отложенная приоритетная задача
Система пытается выполнить приоритетную задачу как можно скорее после ее вызова. Однако, как и в случае с другими типами задач, система может отложить запуск новой приоритетной задачи, например в следующих случаях:
- Load (Нагрузка). Нагрузка на систему слишком высока. Это может произойти, если запущено слишком много заданий или системе не хватает памяти.
- Quota. Превышена квота на приоритетные задачи. Для приоритетных задач используется система квот, основанная на группах App Standby. Она ограничивает максимальное время выполнения в рамках скользящего временного окна. Квоты для приоритетных задач строже, чем для других типов фоновых заданий.
Запланировать периодическую работу
Иногда приложению может потребоваться периодически выполнять определенные задачи. Например, вы можете периодически создавать резервные копии данных, скачивать новый контент в приложение или загружать журналы на сервер.
Ниже показано, как с помощью PeriodicWorkRequest создать объект WorkRequest, который будет выполняться периодически.
Kotlin
val saveRequest =
PeriodicWorkRequestBuilder<SaveImageToFileWorker>(1, TimeUnit.HOURS)
// Additional configuration
.build()
Java
PeriodicWorkRequest saveRequest =
new PeriodicWorkRequest.Builder(SaveImageToFileWorker.class, 1, TimeUnit.HOURS)
// Constraints
.build();
В этом примере работы запланированы с интервалом в один час.
Интервал – это минимальное время между повторами. Точное время выполнения зависит от ограничений, заданных в объекте WorkRequest, и оптимизации, выполняемой системой.
Гибкие интервалы бега
Если для вашей задачи важно время выполнения, вы можете настроить PeriodicWorkRequest так, чтобы она запускалась в гибкий период внутри каждого интервала, как показано на рисунке 1.

Рисунок 1. На диаграмме показаны повторяющиеся интервалы с гибким периодом, в течение которого может выполняться работа.
Чтобы определить периодическую работу с гибким периодом, при создании PeriodicWorkRequest передайте flexInterval вместе с repeatInterval. Гибкий период начинается в repeatInterval - flexInterval и продолжается до конца интервала.
Ниже приведен пример периодической задачи, которая может выполняться в течение последних 15 минут каждого часа.
Kotlin
val myUploadWork = PeriodicWorkRequestBuilder<SaveImageToFileWorker>(
1, TimeUnit.HOURS, // repeatInterval (the period cycle)
15, TimeUnit.MINUTES) // flexInterval
.build()
Java
WorkRequest saveRequest =
new PeriodicWorkRequest.Builder(SaveImageToFileWorker.class,
1, TimeUnit.HOURS,
15, TimeUnit.MINUTES)
.build();
Интервал повторения должен быть больше или равен PeriodicWorkRequest.MIN_PERIODIC_INTERVAL_MILLIS, а гибкий интервал – больше или равен PeriodicWorkRequest.MIN_PERIODIC_FLEX_MILLIS`.
Влияние ограничений на периодическую работу
Вы можете применить ограничения к периодической работе. Например, вы можете добавить ограничение, чтобы задача выполнялась только тогда, когда устройство пользователя заряжается. В этом случае, даже если заданный интервал повторения пройдет, PeriodicWorkRequest не запустится, пока не будет выполнено это условие. Это может привести к задержке или даже пропуску выполнения, если условия не будут выполнены в течение интервала выполнения.
Ограничения на работе
Constraints гарантирует, что работа будет отложена до тех пор, пока не будут выполнены оптимальные условия. В WorkManager доступны следующие ограничения:
| NetworkType | Ограничивает тип сети, необходимой для выполнения работы.
например Wi-Fi (UNMETERED).
|
| BatteryNotLow | Если задано значение true, задача не будет выполняться, когда устройство находится в режиме низкого заряда батареи. |
| RequiresCharging | Если задано значение true, задача будет выполняться, только когда устройство заряжается. |
| DeviceIdle | Если задано значение true, то для выполнения задачи устройство пользователя должно бездействовать. Это может быть полезно для выполнения пакетных операций, которые в противном случае могут негативно повлиять на производительность других приложений, активно работающих на устройстве пользователя. |
| StorageNotLow | Если задано значение true, задача не будет выполняться, если на устройстве пользователя недостаточно места. |
Чтобы создать набор ограничений и связать его с задачей, создайте экземпляр Constraints с помощью Constraints.Builder() и назначьте его WorkRequest.Builder().
Например, следующий код создает запрос на работу, который выполняется, только когда устройство пользователя заряжается и подключено к Wi-Fi:
Kotlin
val constraints = Constraints.Builder()
.setRequiredNetworkType(NetworkType.UNMETERED)
.setRequiresCharging(true)
.build()
val myWorkRequest: WorkRequest =
OneTimeWorkRequestBuilder<MyWork>()
.setConstraints(constraints)
.build()
Java
Constraints constraints = new Constraints.Builder()
.setRequiredNetworkType(NetworkType.UNMETERED)
.setRequiresCharging(true)
.build();
WorkRequest myWorkRequest =
new OneTimeWorkRequest.Builder(MyWork.class)
.setConstraints(constraints)
.build();
Если указано несколько ограничений, задача будет выполняться, только когда соблюдены все из них.
Если ограничение перестанет выполняться во время работы, WorkManager остановит Worker. Работа будет возобновлена, когда все ограничения будут соблюдены.
Отложенная работа
Если у задачи нет ограничений или все они соблюдены, когда задача поставлена в очередь, система может выполнить ее немедленно. Если вы не хотите, чтобы работа выполнялась немедленно, вы можете указать, чтобы она запускалась после минимальной начальной задержки.
Вот пример того, как настроить запуск задачи не ранее чем через 10 минут после ее постановки в очередь.
Kotlin
val myWorkRequest = OneTimeWorkRequestBuilder<MyWork>()
.setInitialDelay(10, TimeUnit.MINUTES)
.build()
Java
WorkRequest myWorkRequest =
new OneTimeWorkRequest.Builder(MyWork.class)
.setInitialDelay(10, TimeUnit.MINUTES)
.build();
В примере показано, как задать начальную задержку для OneTimeWorkRequest, но вы также можете задать ее для PeriodicWorkRequest. В этом случае будет отложен только первый запуск периодической работы.
Правила повторных попыток и задержки
Если вам нужно, чтобы WorkManager повторил попытку, вы можете вернуть Result.retry() из своего воркера. Затем выполнение задачи переносится в соответствии с задержкой экспоненциального откладывания и правилами экспоненциального откладывания.
Задержка экспоненциального уменьшения определяет минимальное время ожидания перед повторной попыткой выполнения работы после первой попытки. Это значение не может быть меньше 10 секунд (или MIN_BACKOFF_MILLIS).
Правила экспоненциальной задержки определяют, как задержка должна увеличиваться со временем для последующих попыток. WorkManager поддерживает два правила задержки:
LINEARиEXPONENTIAL.
У каждого запроса на выполнение работы есть правила и задержка экспоненциального увеличения интервалов между попытками. По умолчанию используется политика EXPONENTIAL с задержкой в 30 секунд, но вы можете переопределить ее в конфигурации запроса на работу.
Ниже приведен пример настройки задержки и политики экспоненциальной выдержки.
Kotlin
val myWorkRequest = OneTimeWorkRequestBuilder<MyWork>()
.setBackoffCriteria(
BackoffPolicy.LINEAR,
WorkRequest.MIN_BACKOFF_MILLIS,
TimeUnit.MILLISECONDS)
.build()
Java
WorkRequest myWorkRequest =
new OneTimeWorkRequest.Builder(MyWork.class)
.setBackoffCriteria(
BackoffPolicy.LINEAR,
WorkRequest.MIN_BACKOFF_MILLIS,
TimeUnit.MILLISECONDS)
.build();
В этом примере минимальная задержка экспоненциального уменьшения частоты запросов установлена на минимально допустимое значение – 10 секунд. Поскольку правило имеет значение LINEAR, интервал между повторными попытками будет увеличиваться примерно на 10 секунд. Например, если при первом запуске возвращается Result.retry(), то следующая попытка будет предпринята через 10 секунд, а затем через 20, 30, 40 и т. д., если при последующих попытках по-прежнему будет возвращаться Result.retry(). Если бы правило экспоненциальной задержки было установлено на EXPONENTIAL, последовательность повторных попыток была бы ближе к 20, 40 и 80.
Как добавлять цели в задания
У каждого запроса на выполнение задачи есть уникальный идентификатор, который можно использовать, чтобы отменить задачу или отслеживать ее выполнение.
Если у вас есть группа логически связанных работ, вам также может быть полезно пометить эти рабочие элементы. Теги позволяют работать с группой запросов на работу.
Например, WorkManager.cancelAllWorkByTag(String) отменяет все запросы на работу с определенным тегом, а WorkManager.getWorkInfosByTag(String) возвращает список объектов WorkInfo, которые можно использовать для определения текущего состояния работы.
В следующем примере показано, как добавить тег "cleanup" в код:
Kotlin
val myWorkRequest = OneTimeWorkRequestBuilder<MyWork>()
.addTag("cleanup")
.build()
Java
WorkRequest myWorkRequest =
new OneTimeWorkRequest.Builder(MyWork.class)
.addTag("cleanup")
.build();
Наконец, к одному запросу на работу можно добавить несколько тегов. Внутренне эти теги хранятся как набор строк. Чтобы получить набор тегов, связанных с WorkRequest, можно использовать WorkInfo.getTags().
Из класса Worker можно получить набор тегов с помощью ListenableWorker.getTags().
Назначьте входные данные
Для выполнения работы могут потребоваться входные данные. Например, для задачи, которая обрабатывает загрузку изображения, может потребоваться URI загружаемого изображения в качестве входных данных.
Входные значения хранятся в виде пар "ключ-значение" в объекте Data и могут быть заданы в запросе на выполнение работы. WorkManager передаст входные данные Data в задачу при ее выполнении. Класс Worker может получить доступ к входным аргументам, вызвав Worker.getInputData(). В следующем коде показано, как создать экземпляр Worker, которому требуются входные данные, и как отправить его в запросе на работу.
Kotlin
// Define the Worker requiring input
class UploadWork(appContext: Context, workerParams: WorkerParameters)
: Worker(appContext, workerParams) {
override fun doWork(): Result {
val imageUriInput =
inputData.getString("IMAGE_URI") ?: return Result.failure()
uploadFile(imageUriInput)
return Result.success()
}
...
}
// Create a WorkRequest for your Worker and sending it input
val myUploadWork = OneTimeWorkRequestBuilder<UploadWork>()
.setInputData(workDataOf(
"IMAGE_URI" to "http://..."
))
.build()
Java
// Define the Worker requiring input
public class UploadWork extends Worker {
public UploadWork(Context appContext, WorkerParameters workerParams) {
super(appContext, workerParams);
}
@NonNull
@Override
public Result doWork() {
String imageUriInput = getInputData().getString("IMAGE_URI");
if(imageUriInput == null) {
return Result.failure();
}
uploadFile(imageUriInput);
return Result.success();
}
...
}
// Create a WorkRequest for your Worker and sending it input
WorkRequest myUploadWork =
new OneTimeWorkRequest.Builder(UploadWork.class)
.setInputData(
new Data.Builder()
.putString("IMAGE_URI", "http://...")
.build()
)
.build();
Аналогичным образом можно использовать класс Data для вывода возвращаемого значения.
Дальнейшие действия
На странице Статусы и наблюдение вы узнаете больше о статусах работы и о том, как отслеживать ее ход.