Цепная работа

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

Чтобы создать цепочку работ, вы можете использовать WorkManager.beginWith(OneTimeWorkRequest) или WorkManager.beginWith(List<OneTimeWorkRequest>) , каждый из которых возвращает экземпляр WorkContinuation .

Затем WorkContinuation можно использовать для добавления зависимых экземпляров OneTimeWorkRequest с помощью then(OneTimeWorkRequest) или then(List<OneTimeWorkRequest>) .

Каждый вызов WorkContinuation.then(...) возвращает новый экземпляр WorkContinuation . Если вы добавите List экземпляров OneTimeWorkRequest , эти запросы потенциально могут выполняться параллельно.

Наконец, вы можете использовать метод WorkContinuation.enqueue() для enqueue() вашей цепочки WorkContinuation .

Давайте посмотрим на пример. В этом примере настроено выполнение трех разных рабочих заданий (возможно, параллельно). Результаты этих рабочих процессов затем объединяются и передаются в задание кэширующего рабочего процесса. Наконец, выходные данные этого задания передаются в Worker загрузки, который загружает результаты на удаленный сервер.

Котлин

WorkManager.getInstance(myContext)
   // Candidates to run in parallel
   .beginWith(listOf(plantName1, plantName2, plantName3))
   // Dependent work (only runs after all previous work in chain)
   .then(cache)
   .then(upload)
   // Call enqueue to kick things off
   .enqueue()

Ява

WorkManager.getInstance(myContext)
   // Candidates to run in parallel
   .beginWith(Arrays.asList(plantName1, plantName2, plantName3))
   // Dependent work (only runs after all previous work in chain)
   .then(cache)
   .then(upload)
   // Call enqueue to kick things off
   .enqueue();

Слияния входов

При объединении экземпляров OneTimeWorkRequest выходные данные родительских запросов на работу передаются в качестве входных данных дочерним элементам. Таким образом, в приведенном выше примере выходные данные plantName1 , plantName2 и plantName3 будут переданы в качестве входных данных для запроса cache .

Чтобы управлять входными данными из нескольких родительских рабочих запросов, WorkManager использует InputMerger .

WorkManager предоставляет два разных типа InputMerger :

  • OverwritingInputMerger пытается добавить все ключи со всех входов в выход. В случае конфликтов он перезаписывает ранее установленные ключи.

  • ArrayCreatingInputMerger пытается объединить входные данные, создавая при необходимости массивы.

Если у вас более конкретный вариант использования, вы можете написать свой собственный, создав подкласс InputMerger .

ПерезаписьInputMerger

OverwritingInputMerger — метод слияния по умолчанию. Если при слиянии возникают конфликты ключей, то последнее значение ключа перезапишет все предыдущие версии в результирующих выходных данных.

Например, если каждый из входных данных завода имеет ключ, соответствующий соответствующим именам переменных ( "plantName1" , "plantName2" и "plantName3" ), то данные, передаваемые в работник cache , будут иметь три пары ключ-значение.

Диаграмма, показывающая три задания, передающих разные выходные данные следующему заданию в цепочке. Поскольку все три выхода имеют разные ключи, следующее задание получит три пары ключ/значение.

Если возникает конфликт, то «побеждает» последний завершивший рабочий процесс, и его значение передается в cache .

Диаграмма, показывающая три задания, передающих результаты следующему заданию в цепочке. В этом случае два из этих заданий производят выходные данные с одним и тем же ключом. В результате следующее задание получает две пары ключ/значение, при этом один из конфликтующих выходных данных удаляется.

Поскольку ваши рабочие запросы выполняются параллельно, у вас нет гарантий относительно порядка их выполнения. В приведенном выше примере plantName1 может содержать значение "tulip" или "elm" , в зависимости от того, какое значение записано последним. Если у вас есть вероятность конфликта ключей и вам необходимо сохранить все выходные данные при слиянии, лучшим вариантом может быть ArrayCreatingInputMerger .

ArrayCreatingInputMerger

В приведенном выше примере, учитывая, что мы хотим сохранить выходные данные всех рабочих имен объектов, мы должны использовать ArrayCreatingInputMerger .

Котлин

val cache: OneTimeWorkRequest = OneTimeWorkRequestBuilder<PlantWorker>()
   .setInputMerger(ArrayCreatingInputMerger::class)
   .setConstraints(constraints)
   .build()

Ява

OneTimeWorkRequest cache = new OneTimeWorkRequest.Builder(PlantWorker.class)
       .setInputMerger(ArrayCreatingInputMerger.class)
       .setConstraints(constraints)
       .build();

ArrayCreatingInputMerger соединяет каждый ключ с массивом. Если каждый из ключей уникален, то результатом будет серия одноэлементных массивов.

Диаграмма, показывающая три задания, передающих разные выходные данные следующему заданию в цепочке. Следующему заданию передаются три массива, по одному на каждый выходной ключ. Каждый массив имеет один элемент.

Если есть какие-либо коллизии ключей, все соответствующие значения группируются в массив.

Диаграмма, показывающая три задания, передающих результаты следующему заданию в цепочке. В этом случае два из этих заданий производят выходные данные с одним и тем же ключом. Следующему заданию передаются два массива, по одному на каждый ключ. Один из этих массивов имеет два элемента, поскольку с этим ключом было два выхода.

Объединение и рабочие статусы

Цепочки OneTimeWorkRequest выполняются последовательно, пока их работа завершается успешно (то есть они возвращают Result.success() ). Рабочие запросы могут завершиться неудачно или быть отменены во время выполнения, что оказывает влияние на зависимые рабочие запросы.

Когда первый OneTimeWorkRequest ставится в очередь в цепочке рабочих запросов, все последующие рабочие запросы блокируются до тех пор, пока работа этого первого рабочего запроса не будет завершена.

Диаграмма, показывающая цепочку должностей. Первое задание ставится в очередь; все последующие задания блокируются до завершения первого.

После постановки в очередь и выполнения всех рабочих ограничений начинается выполнение первого рабочего запроса. Если работа успешно завершена в корне OneTimeWorkRequest или List<OneTimeWorkRequest> (то есть он возвращает Result.success() ), то следующий набор зависимых рабочих запросов будет поставлен в очередь.

Диаграмма, показывающая цепочку должностей. Первое задание выполнено успешно, и два его непосредственных преемника поставлены в очередь. Остальные задания блокируются, а предыдущие задания завершаются.

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

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

Диаграмма, показывающая цепочку должностей. Одно из заданий завершилось неудачно, но для него была определена политика отсрочки выполнения. Это задание будет запущено повторно по истечении соответствующего периода времени. Задания, следующие за ним в цепочке, блокируются до тех пор, пока они не будут выполнены успешно.

Дополнительные сведения об определении пользовательских стратегий повторных попыток см. в разделе Политика повторных попыток и отсрочки .

Если эта политика повторных попыток не определена или исчерпана или вы иным образом достигли некоторого состояния, в котором OneTimeWorkRequest возвращает Result.failure() , тогда этот рабочий запрос и все зависимые рабочие запросы помечаются как FAILED.

Диаграмма, показывающая цепочку должностей. Одно задание завершилось неудачно, и его невозможно повторить. В результате все задания после него в цепочке также терпят неудачу.

Та же логика применяется при отмене OneTimeWorkRequest . Любые зависимые запросы на работу также помечаются CANCELLED , и их работа не будет выполнена.

Диаграмма, показывающая цепочку должностей. Одно задание отменено. В результате все задания в цепочке после него также отменяются.

Обратите внимание: если вы добавили больше рабочих запросов в цепочку, которая потерпела неудачу или отменила рабочие запросы, то ваш вновь добавленный рабочий запрос также будет помечен как FAILED или CANCELLED соответственно. Если вы хотите расширить работу существующей цепочки, смотрите APPEND_OR_REPLACE в ExistingWorkPolicy .

При создании цепочек рабочих запросов зависимые рабочие запросы должны определять политики повтора, чтобы гарантировать, что работа всегда выполняется своевременно. Неудачные рабочие запросы могут привести к неполным цепочкам и/или неожиданному состоянию.

Для получения дополнительной информации см. Отмена и остановка работы .