ОАО «Российская Авиакомпания ЭРЛЕН»

Russian Airlines Company "Airlen"

Ваш внешний IP: 3.239.76.25

Запуск фоновых задач в Android с помощью WorkManager: часть 3

Предыдущая статья из этой серии:Запуск фоновых задач в Android с помощью WorkManager: часть 2

Последовательность задач

В этом руководстве будут рассмотрены методы запуска задач в определенном последовательном порядке.

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

Это можно сделать с помощью трех последовательных задач:

  • скачать архив
  • распаковка архива
  • обработка файлов

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

Во-первых, давайте удостоверимся, что задачи, запущенные обычным образом, будут выполняться параллельно. Запускаем сразу три задачи:

val worker1: WorkRequest = OneTimeWorkRequestBuilder<Worker1>()
    .build()  

val worker2: WorkRequest = OneTimeWorkRequestBuilder<Worker2>()  
    .build()  

val worker3: WorkRequest = OneTimeWorkRequestBuilder<Worker3>()  
    .build()  

WorkManager  
    .getInstance(this)  
    .enqueue(listOf(worker1, worker2, worker3))

Смотрим лог:

2023-04-18 21:07:05 18984-19015 Worker2  D  doWork: start
2023-04-18 21:07:05 18984-19016 Worker3  D  doWork: start
2023-04-18 21:07:05 18984-19014 Worker1  D  doWork: start

2023-04-18 21:07:06 18984-19014 Worker1  D  doWork: end
2023-04-18 21:07:06 18984-19016 Worker3  D  doWork: end
2023-04-18 21:07:06 18984-19015 Worker2  D  doWork: end

Задачи запускались в  21:07:05и выполнялись параллельно в разных потоках, и каждый выполнялся в свое время.

Мы видели параллельное исполнение. Теперь выполним их последовательно. Передаем в beginWithметод первую задачу и тем самым создаем начало последовательности задач. Далее, вызвав thenметод, добавляем в последовательность вторую и третью задачи. И с помощью enqueueметода отправляем эту последовательность на запуск.

Результат:

2023-04-18 21:28:59 20007-20036 Worker1  D  doWork: start
2023-04-18 21:29:00 20007-20036 Worker1  D  doWork: end
2023-04-18 21:29:00 20007-20044 Worker2  D  doWork: start
2023-04-18 21:29:01 20007-20044 Worker2  D  doWork: end
2023-04-18 21:29:01 20007-20045 Worker3  D  doWork: start
2023-04-18 21:29:02 20007-20045 Worker3  D  doWork: end

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

Как критерии повлияют на выполнение последовательности задач?

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

Давайте посмотрим на пример.

Пусть у второй задачи есть критерий – наличие интернета. Отключаем интернет на устройстве и запускаем последовательность. Первой задаче все равно; он работает. Приходит очередь второй задачи, а интернета нет; поэтому вторая задача откладывается, а третья задача может быть запущена только после завершения второй. Так что приходится ждать. Включаем интернет, выполняется второе задание, а за ним и третье.

Если какая-либо задача в последовательности заканчивается статусом FAILURE, вся цепочка будет остановлена.

Мы можем комбинировать последовательное и параллельное выполнение задач.

WorkManager  
    .getInstance(this)  
    .beginWith(listOf(worker1, worker2))  
    .then(listOf(worker3, worker4))  
    .then(worker5)  
    .enqueue()

Здесь мы формируем последовательность, но при этом указываем две задачи для первого (beginWith) и второго (first then) шага последовательности.

В результате задачи worker1и worker2будут выполняться первыми, а выполняться они будут параллельно. После этого worker3и worker4будут выполняться, также параллельно друг другу. И после этого – worker5.

В логах это будет выглядеть так:

2023-04-18 21:41:31 20434-20464 Worker1  D  doWork: start
2023-04-18 21:41:31 20434-20465 Worker2  D  doWork: start
2023-04-18 21:41:32 20434-20464 Worker1  D  doWork: end
2023-04-18 21:41:32 20434-20465 Worker2  D  doWork: end
2023-04-18 21:41:32 20434-20476 Worker3  D  doWork: start
2023-04-18 21:41:32 20434-20464 Worker4  D  doWork: start
2023-04-18 21:41:33 20434-20476 Worker3  D  doWork: end
2023-04-18 21:41:33 20434-20464 Worker4  D  doWork: end
2023-04-18 21:41:33 20434-20465 Worker5  D  doWork: start
2023-04-18 21:41:34 20434-20465 Worker5  D  doWork: end

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

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

Вот как это делается:

val chain12: WorkContinuation = WorkManager  
    .getInstance(this)  
    .beginWith(worker1)  
    .then(worker2)  

val chain34: WorkContinuation = WorkManager  
    .getInstance(this)  
    .beginWith(worker3)  
    .then(worker4)  

WorkContinuation.combine(listOf(chain12, chain34))  
    .then(worker5)  
    .enqueue()

WorkContinuationпредставляет собой последовательность задач. Создаем chain12последовательность, состоящую из первой и второй задач, и chain34последовательность, состоящую из третьей и четвертой задач. Чтобы эти последовательности выполнялись параллельно друг другу, мы передаем их в combineметод. Затем мы передаем методу пятую задачу then, которая запускается после того, как все последовательности из combineбудут выполнены.

Результат:

2023-04-19 15:58:20  1511-1534  Worker1 D  doWork: start
2023-04-19 15:58:20  1511-1535  Worker3 D  doWork: start
2023-04-19 15:58:21  1511-1534  Worker1 D  doWork: end
2023-04-19 15:58:21  1511-1535  Worker3 D  doWork: end
2023-04-19 15:58:21  1511-1571  Worker2 D  doWork: start
2023-04-19 15:58:21  1511-1534  Worker4 D  doWork: start
2023-04-19 15:58:22  1511-1571  Worker2 D  doWork: end
2023-04-19 15:58:22  1511-1534  Worker4 D  doWork: end
2023-04-19 15:58:22  1511-1571  Worker5 D  doWork: start
2023-04-19 15:58:23  1511-1571  Worker5 D  doWork: end

Запускаются первая и третья задачи, т.е. последовательности начинают выполняться параллельно. Когда обе последовательности выполнены, начинается пятая задача.

Уникальная работа

Мы можем сделать последовательность задач уникальной. Для этого мы запускаем последовательность с помощью метода beginUniqueWork.

private fun work() {  

    val worker1 = OneTimeWorkRequestBuilder<Worker1>()  
        .build()   

    val worker3 = OneTimeWorkRequestBuilder<Worker3>()  
        .build()  

    val worker5 = OneTimeWorkRequestBuilder<Worker5>()  
        .build()  

    WorkManager.getInstance(this)  
        .beginUniqueWork("work123", ExistingWorkPolicy.REPLACE, worker1)  
        .then(worker3)  
        .then(worker5)  
        .enqueue()  

}

findViewById<AppCompatButton>(R.id.startWork).setOnClickListener {  
    Log.e(TAG, "enqueue REPLACE")  
    work()  
}

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

Мы указали REPLACE в качестве режима. Это означает, что если последовательность с тем же именем уже запущена, то при следующем запуске текущая последовательность будет остановлена ​​и запущена новая.

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

2023-04-19 16:52:32 17809-17809 WorkManagerActivity3 E  enqueue REPLACE
2023-04-19 16:52:33 17809-17882 Worker1              D  doWork: start
2023-04-19 16:52:38 17809-17882 Worker1              D  doWork: end
2023-04-19 16:52:38 17809-17914 Worker3              D  doWork: start
2023-04-19 16:52:43 17809-17914 Worker3              D  doWork: end
2023-04-19 16:52:43 17809-17952 Worker5              D  doWork: start

2023-04-19 16:52:46 17809-17809 WorkManagerActivity3 E  enqueue REPLACE
2023-04-19 16:52:46 17809-17880 Worker5              D  onStopped
2023-04-19 16:52:46 17809-17882 Worker1              D  doWork: start
2023-04-19 16:52:48 17809-17952 Worker5              D  doWork: end
2023-04-19 16:52:51 17809-17882 Worker1              D  doWork: end
2023-04-19 16:52:51 17809-17914 Worker3              D  doWork: start
2023-04-19 16:52:56 17809-17914 Worker3              D  doWork: end
2023-04-19 16:52:56 17809-17952 Worker5              D  doWork: start
2023-04-19 16:53:01 17809-17952 Worker5              D  doWork: end

16:52:32 — это первый запуск последовательности. Задачи начинают выполняться одна за другой.

16:52:46 – пока работает MyWorker5, создаю и запускаю такую ​​же последовательность с тем же именем – work123. Выполняемая в данный момент последовательность останавливается и запускается новая.

Режим KEEP будет поддерживать текущую выполняемую последовательность. Новый будет проигнорирован.

Код:

WorkManager.getInstance(this)  
    .beginUniqueWork("work123", ExistingWorkPolicy.KEEP, worker1)  
    .then(worker3)  
    .then(worker5)  
    .enqueue()

Журналы:

2023-04-19 17:05:17 20030-20030 WorkManagerActivity3 E  enqueue KEEP
2023-04-19 17:05:18 20030-20207 Worker1              D  doWork: start
2023-04-19 17:05:23 20030-20207 Worker1              D  doWork: end
2023-04-19 17:05:23 20030-20227 Worker3              D  doWork: start
2023-04-19 17:05:28 20030-20227 Worker3              D  doWork: end
2023-04-19 17:05:28 20030-20272 Worker5              D  doWork: start
2023-04-19 17:05:29 20030-20030 WorkManagerActivity3 E  enqueue KEEP
2023-04-19 17:05:33 20030-20272 Worker5              D  doWork: end

17:05:29 – Я попытался запустить последовательность еще раз, но был проигнорирован, потому что в работе уже есть последовательность с таким названием.

Режим APPEND запустит новую последовательность после выполнения текущей.

Код:

WorkManager.getInstance(this)  
    .beginUniqueWork("work123", ExistingWorkPolicy.APPEND, worker1)  
    .then(worker3)  
    .then(worker5)  
    .enqueue()

Журналы:

2023-04-19 17:10:28 21636-21636 WorkManagerActivity3 E  enqueue APPEND
2023-04-19 17:10:28 21636-21730 Worker1              D  doWork: start
2023-04-19 17:10:33 21636-21730 Worker1              D  doWork: end
2023-04-19 17:10:33 21636-21784 Worker3              D  doWork: start
2023-04-19 17:10:38 21636-21784 Worker3              D  doWork: end
2023-04-19 17:10:38 21636-21836 Worker5              D  doWork: start
2023-04-19 17:10:39 21636-21636 WorkManagerActivity3 E  enqueue APPEND
2023-04-19 17:10:43 21636-21836 Worker5              D  doWork: end
2023-04-19 17:10:43 21636-21730 Worker1              D  doWork: start
2023-04-19 17:10:48 21636-21730 Worker1              D  doWork: end
2023-04-19 17:10:48 21636-21784 Worker3              D  doWork: start
2023-04-19 17:10:53 21636-21784 Worker3              D  doWork: end
2023-04-19 17:10:53 21636-21836 Worker5              D  doWork: start
2023-04-19 17:10:58 21636-21836 Worker5              D  doWork: end

17:10:39 – текущая последовательность не прерывалась, а новая запускалась сразу после окончания текущей.

Будьте осторожны с этим режимом, т.к. ошибка в текущей последовательности может привести к тому, что новая последовательность не запустится.

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

 

реагировать на историю с копией
отнеситесь к истории с душой
Февраль 2024
Пн Вт Ср Чт Пт Сб Вс
 1234
567891011
12131415161718
19202122232425
26272829  

Сервер: 29.02.2024 07:02