После определения объекта Worker и объекта WorkRequest последний шаг — добавить задачу в очередь. Самый простой способ добавить задачу в очередь — вызвать метод enqueue() объекта WorkManager, передав ему объект WorkRequest который вы хотите выполнить.
Котлин
val myWork: WorkRequest = // ... OneTime or PeriodicWork
WorkManager.getInstance(requireContext()).enqueue(myWork)
Java
WorkRequest myWork = // ... OneTime or PeriodicWork
WorkManager.getInstance(requireContext()).enqueue(myWork);
Будьте осторожны при постановке задач в очередь, чтобы избежать дублирования. Например, приложение может пытаться загружать свои логи в бэкэнд-сервис каждые 24 часа. Если вы не будете внимательны, вы можете поставить в очередь одну и ту же задачу много раз, даже если задание нужно выполнить всего один раз. Для достижения этой цели вы можете запланировать выполнение задачи как уникальное задание .
Уникальная работа
Уникальное произведение — это мощная концепция, гарантирующая наличие только одного экземпляра произведения с определенным именем одновременно. В отличие от идентификаторов, уникальные имена удобочитаемы и указываются разработчиком, а не генерируются автоматически WorkManager. В отличие от тегов , уникальные имена связаны только с одним экземпляром произведения.
Уникальные задачи могут применяться как к разовым, так и к периодическим задачам. Вы можете создать уникальную последовательность задач, вызвав один из этих методов, в зависимости от того, планируете ли вы повторяющуюся или разовую работу.
-
WorkManager.enqueueUniqueWork()для выполнения разовой работы -
WorkManager.enqueueUniquePeriodicWork()для периодической работы
Оба метода принимают 3 аргумента:
- uniqueWorkName —
Stringиспользуемая для уникальной идентификации запроса на выполнение работы. - existingWorkPolicy —
enum, указывающее WorkManager, что делать, если уже существует незавершенная цепочка работ с таким уникальным именем. Дополнительную информацию см. в разделе «Политика разрешения конфликтов» . - work - Запрос на выполнение
WorkRequestдля планирования.
Используя уникальные методы работы, мы можем исправить отмеченную ранее проблему с дублированием расписаний.
Котлин
val sendLogsWorkRequest =
PeriodicWorkRequestBuilder<SendLogsWorker>(24, TimeUnit.HOURS)
.setConstraints(Constraints.Builder()
.setRequiresCharging(true)
.build()
)
.build()
WorkManager.getInstance(this).enqueueUniquePeriodicWork(
"sendLogs",
ExistingPeriodicWorkPolicy.KEEP,
sendLogsWorkRequest
)
Java
PeriodicWorkRequest sendLogsWorkRequest = new
PeriodicWorkRequest.Builder(SendLogsWorker.class, 24, TimeUnit.HOURS)
.setConstraints(new Constraints.Builder()
.setRequiresCharging(true)
.build()
)
.build();
WorkManager.getInstance(this).enqueueUniquePeriodicWork(
"sendLogs",
ExistingPeriodicWorkPolicy.KEEP,
sendLogsWorkRequest);
Теперь, если код выполняется, когда задание sendLogs уже находится в очереди, существующее задание сохраняется, и новое задание не добавляется.
Уникальные последовательности действий также могут быть полезны, если вам нужно постепенно выстраивать длинную цепочку задач. Например, приложение для редактирования фотографий может позволять пользователям отменять длинную цепочку действий. Каждая из этих операций отмены может занять некоторое время, но они должны выполняться в правильном порядке. В этом случае приложение может создать цепочку «отмены» и добавлять каждую операцию отмены к цепочке по мере необходимости. Подробнее см. раздел «Последовательность действий» .
Политика разрешения конфликтов
При планировании уникальных задач необходимо указать WorkManager, какое действие следует предпринять в случае возникновения конфликта. Это делается путем передачи перечисления (enum) при постановке задачи в очередь.
Для разовой работы вы предоставляете ExistingWorkPolicy , которая поддерживает 4 варианта разрешения конфликта.
-
REPLACEсуществующую работу новой. Эта опция отменяет существующую работу. -
KEEPсуществующую работу и игнорируйте новую. -
APPENDновую работу в конец существующей. Эта политика приведет к тому, что ваша новая работа будет связана с существующей и будет выполняться после завершения последней.
Существующая работа становится необходимым условием для новой работы. Если существующая работа получает CANCELLED или FAILED , новая работа также CANCELLED или FAILED . Если вы хотите, чтобы новая работа выполнялась независимо от статуса существующей работы, используйте вместо этого APPEND_OR_REPLACE .
- Функция
APPEND_OR_REPLACEработает аналогично функцииAPPEND, за исключением того, что она не зависит от статуса предварительной работы. Если существующая работа имеетCANCELLEDилиFAILED, новая работа все равно будет выполнена.
Для периодической работы вы предоставляете ExistingPeriodicWorkPolicy , которая поддерживает 2 параметра: REPLACE и KEEP . Эти параметры функционируют так же, как и их аналоги в ExistingWorkPolicy.
Наблюдение за вашей работой
В любой момент после добавления задачи в очередь вы можете проверить ее статус, запросив WorkManager по name , id или связанному с ней tag .
Котлин
// by id
workManager.getWorkInfoById(syncWorker.id) // ListenableFuture<WorkInfo>
// by name
workManager.getWorkInfosForUniqueWork("sync") // ListenableFuture<List<WorkInfo>>
// by tag
workManager.getWorkInfosByTag("syncTag") // ListenableFuture<List<WorkInfo>>
Java
// by id
workManager.getWorkInfoById(syncWorker.id); // ListenableFuture<WorkInfo>
// by name
workManager.getWorkInfosForUniqueWork("sync"); // ListenableFuture<List<WorkInfo>>
// by tag
workManager.getWorkInfosByTag("syncTag"); // ListenableFuture<List<WorkInfo>>
Запрос возвращает объект ListenableFuture типа WorkInfo , который содержит id работы, её теги, текущее State и любой выходной набор данных, полученный с помощью Result.success(outputData) .
Варианты LiveData и Flow для каждого из методов позволяют отслеживать изменения в WorkInfo , зарегистрировав слушатель. Например, если вы хотите отобразить сообщение пользователю после успешного завершения какой-либо работы, вы можете настроить это следующим образом:
Котлин
workManager.getWorkInfoByIdFlow(syncWorker.id)
.collect{ workInfo ->
if(workInfo?.state == WorkInfo.State.SUCCEEDED) {
Snackbar.make(requireView(),
R.string.work_completed, Snackbar.LENGTH_SHORT)
.show()
}
}
Java
workManager.getWorkInfoByIdLiveData(syncWorker.id)
.observe(getViewLifecycleOwner(), workInfo -> {
if (workInfo.getState() != null &&
workInfo.getState() == WorkInfo.State.SUCCEEDED) {
Snackbar.make(requireView(),
R.string.work_completed, Snackbar.LENGTH_SHORT)
.show();
}
});
Сложные рабочие запросы
WorkManager 2.4.0 и более поздние версии поддерживают сложные запросы к поставленным в очередь заданиям с использованием объектов WorkQuery . WorkQuery поддерживает запросы к заданиям по комбинации их тегов, состояния и уникального имени задания.
В следующем примере показано, как найти все задания с тегом "syncTag" , находящиеся в состоянии FAILED " или CANCELLED " и имеющие уникальное имя задания либо " preProcess ", либо " sync ".
Котлин
val workQuery = WorkQuery.Builder
.fromTags(listOf("syncTag"))
.addStates(listOf(WorkInfo.State.FAILED, WorkInfo.State.CANCELLED))
.addUniqueWorkNames(listOf("preProcess", "sync")
)
.build()
val workInfos: ListenableFuture<List<WorkInfo>> = workManager.getWorkInfos(workQuery)
Java
WorkQuery workQuery = WorkQuery.Builder
.fromTags(Arrays.asList("syncTag"))
.addStates(Arrays.asList(WorkInfo.State.FAILED, WorkInfo.State.CANCELLED))
.addUniqueWorkNames(Arrays.asList("preProcess", "sync")
)
.build();
ListenableFuture<List<WorkInfo>> workInfos = workManager.getWorkInfos(workQuery);
Каждый компонент (тег, состояние или имя) в WorkQuery AND с другими компонентами с помощью оператора И. Каждое значение компонента объединяется OR . Например: (name1 OR name2 OR ...) AND (tag1 OR tag2 OR ...) AND (state1 OR state2 OR ...) .
WorkQuery также работает с эквивалентом LiveData, getWorkInfosLiveData() , и эквивалентом Flow, getWorkInfosFlow() .
Отмена и прекращение работ
Если вам больше не нужно выполнять ранее поставленную в очередь задачу, вы можете запросить ее отмену. Отменить задачу можно по ее name , id или по связанному с ней tag .
Котлин
// by id
workManager.cancelWorkById(syncWorker.id)
// by name
workManager.cancelUniqueWork("sync")
// by tag
workManager.cancelAllWorkByTag("syncTag")
Java
// by id
workManager.cancelWorkById(syncWorker.id);
// by name
workManager.cancelUniqueWork("sync");
// by tag
workManager.cancelAllWorkByTag("syncTag");
Внутри системы WorkManager проверяет State задачи. Если задача уже выполнена , ничего не происходит. В противном случае состояние задачи изменяется на CANCELLED , и задача не будет выполняться в будущем. Все задачи WorkRequest , зависящие от этой задачи, также будут CANCELLED ).
RUNNING задачи вызывается метод ListenableWorker.onStopped() . Переопределите этот метод, чтобы обработать возможные действия по очистке ресурсов. Дополнительную информацию см. в разделе «Остановка запущенного рабочего процесса» .
Остановить бегущего рабочего
Существует несколько причин, по которым запущенный Worker может быть остановлен WorkManager:
- Вы явно запросили отмену (например, вызвав
WorkManager.cancelWorkById(UUID)). - В случае уникальной задачи вы явно добавили в очередь новый
WorkRequestс политикойExistingWorkPolicyсо значениемREPLACE. СтарыйWorkRequestнемедленно считается отмененным. - Ограничения вашей работы больше не соблюдаются.
- Система дала вашему приложению указание остановить работу по какой-то причине. Это может произойти, если вы превысите 10-минутный лимит выполнения. Работа будет запланирована на повторное выполнение позже.
В этих условиях ваш работник будет остановлен.
Вам следует совместно прервать всю незавершенную работу и освободить все ресурсы, которые удерживает ваш Worker. Например, на этом этапе следует закрыть открытые дескрипторы баз данных и файлов. В вашем распоряжении два механизма для определения момента остановки работы Worker.
обработчик события onStopped()
WorkManager вызывает метод ListenableWorker.onStopped() сразу после остановки вашего Worker. Переопределите этот метод, чтобы закрыть любые ресурсы, которые вы могли удерживать.
свойство isStopped()
Вы можете вызвать метод ListenableWorker.isStopped() , чтобы проверить, был ли ваш воркер уже остановлен. Если вы выполняете длительные или повторяющиеся операции в своем воркере, вам следует часто проверять это свойство и использовать его в качестве сигнала для как можно более быстрой остановки работы.
Примечание: WorkManager игнорирует Result установленный рабочим процессом, получившим сигнал onStop , поскольку этот рабочий процесс уже считается остановленным.