Łączenie łańcuchów

WorkManager umożliwia tworzenie i umieszczanie w kole zadań w łańcuchu, które określają wiele zależnych od siebie zadań i określają ich kolejność. Ta funkcja jest szczególnie przydatna, gdy chcesz wykonać kilka zadań w określonej kolejności.

Aby utworzyć łańcuch zadań, możesz użyć funkcji WorkManager.beginWith(OneTimeWorkRequest) lub WorkManager.beginWith(List<OneTimeWorkRequest>), które zwracają instancję WorkContinuation.

Następnie za pomocą WorkContinuation można dodawać zależne wystąpienia OneTimeWorkRequest za pomocą then(OneTimeWorkRequest) lub then(List<OneTimeWorkRequest>).

Każde wywołanie funkcji WorkContinuation.then(...) zwraca nowy egzemplarz funkcji WorkContinuation. Jeśli dodasz List wystąpień OneTimeWorkRequest, te żądania mogą być wykonywane równolegle.

Na koniec możesz użyć metody WorkContinuation.enqueue(), aby enqueue() łańcuch WorkContinuation.

Przeanalizujmy to na przykładzie. W tym przykładzie 3 różne zadania Worker są skonfigurowane do wykonania (opcjonalnie w drodze równoległej). Wyniki tych zadań są następnie łączone i przekazywane do zadania Workera obsługującego buforowanie. W końcu dane wyjściowe tego zadania są przekazywane do procesu przesyłania, który przesyła wyniki na zdalny serwer.

Kotlin


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

Java


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

Złączenia danych wejściowych

Gdy połączysz instancje OneTimeWorkRequest, dane wyjściowe żądań rodzicielskich zostaną przekazane jako dane wejściowe do podrzędnych. W tym przykładzie dane wyjściowe plantName1, plantName2plantName3 są przekazywane jako dane wejściowe do żądania cache.

Aby zarządzać danymi wejściowymi z wielu nadrzędnych zadań, WorkManager używa interfejsu InputMerger.

WorkManager udostępnia 2 rodzaje InputMerger:

  • OverwritingInputMerger próbuje dodać wszystkie klucze ze wszystkich danych wejściowych do danych wyjściowych. W przypadku konfliktów zastąpi on wcześniej ustawione klucze.

  • ArrayCreatingInputMerger próbuje scalić dane wejściowe, tworząc w razie potrzeby tablice.

Jeśli masz bardziej szczegółowy przypadek użycia, możesz napisać własną klasę podrzędną InputMerger.

OverwritingInputMerger

OverwritingInputMerger to domyślna metoda scalania. Jeśli podczas scalania wystąpią konflikty kluczy, najnowsza wartość klucza zastąpi wszystkie poprzednie wersje w wynikających danych wyjściowych.

Jeśli np. każdy z wejść plant ma klucz pasujący do nazwy odpowiedniej zmiennej ("plantName1", "plantName2""plantName3"), dane przekazywane instancji roboczej cache będą zawierać 3 pary klucz-wartość.

Schemat przedstawiający 3 zadania przekazujące różne dane wyjściowe do następnego zadania w łańcuchu. Wszystkie 3 wyjścia mają różne klucze, więc kolejne zadanie otrzymuje 3 pary klucz-wartość.

Jeśli wystąpi konflikt, „wygrywa” ostatni pracownik, który go ukończył, a jego wartość jest przekazywana do cache.

Schemat przedstawiający 3 zadania przekazujące dane wyjściowe do następnego zadania w łańcuchu. W tym przypadku 2 z tych zadań wygenerują dane wyjściowe z tym samym kluczem. W efekcie kolejne zadanie otrzymuje 2 pary klucz-wartość, a jeden z konfliktujących się wyników jest pomijany.

Twoje żądania robocze są wykonywane równolegle, więc nie masz gwarancji co do kolejności ich wykonywania. W powyższym przykładzie zmienna plantName1 może zawierać wartość "tulip" lub "elm", w zależności od tego, która wartość została zapisana jako ostatnia. Jeśli istnieje ryzyko konfliktu kluczy i musisz zachować wszystkie dane wyjściowe podczas scalania, ArrayCreatingInputMerger może być lepszą opcją.

ArrayCreatingInputMerger

W przypadku powyższego przykładu, ponieważ chcemy zachować dane wyjściowe z wszystkich pracowników fabryki o nazwie Workers, powinniśmy użyć ArrayCreatingInputMerger.

Kotlin


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

Java


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

ArrayCreatingInputMerger łączy każdy klucz z tablicą. Jeśli każdy z kluczy jest niepowtarzalny, wynik to seria tablic jednoelementowych.

Schemat przedstawiający 3 zadania przekazujące różne dane wyjściowe do następnego zadania w łańcuchu. Następnemu zadaniu przekazywane są 3 tablice, po jednej dla każdego klucza danych wyjściowych. Każda tablica ma 1 element.

Jeśli wystąpią kolizje kluczy, wszystkie odpowiadające im wartości zostaną pogrupowane w tablicy.

Schemat przedstawiający 3 zadania przekazujące dane wyjściowe do następnego zadania w łańcuchu. W tym przypadku 2 z tych zadań wygenerują dane wyjściowe z tym samym kluczem. Następnemu zadaniu przekazywane są 2 tablice, po jednej dla każdego klucza. Jeden z tych tablic ma 2 elementy, ponieważ były 2 wyjścia z tym kluczem.

Łańcuchowanie i stany pracy

Łańcuchy OneTimeWorkRequest są wykonywane sekwencyjnie, dopóki ich wykonanie się powiedzie (czyli zwrócą wartość Result.success()). Żądania o wykonanie pracy mogą się nie udać lub zostać anulowane podczas wykonywania, co ma wpływ na zależne żądania o wykonanie pracy.

Gdy pierwsze OneTimeWorkRequest zostanie umieszczone w kolejce w łańcuchu żądań pracy, wszystkie kolejne żądania pracy są blokowane do czasu zakończenia pracy związanej z pierwszym żądaniem.

Diagram przedstawiający łańcuch zadań. Pierwsze zadanie jest umieszczane w kolejce; wszystkie kolejne zadania są blokowane do czasu ukończenia pierwszego.

Gdy zadanie zostanie umieszczone w kolejce i spełnione zostaną wszystkie ograniczenia, rozpocznie się wykonywanie pierwszego żądania pracy. Jeśli zadanie zostanie wykonane w korzeniach OneTimeWorkRequest lub List<OneTimeWorkRequest> (czyli zwróci wartość Result.success()), następny zestaw zależnych zadań zostanie umieszczony w kole.

Diagram przedstawiający łańcuch zadań. Pierwsze zadanie zostało ukończone, a dwa następne są w kolejce. Pozostałe zadania są blokowane do czasu zakończenia poprzednich zadań.

Dopóki każde żądanie pracy zostanie zrealizowane, ten sam wzór będzie się rozprzestrzeniał w dalszej części łańcucha żądań pracy, aż do momentu, gdy wszystkie zadania zostaną ukończone. Chociaż jest to najprostszy i najczęściej preferowany przypadek, stany błędów są równie ważne.

Jeśli podczas przetwarzania Twojego żądania pracy wystąpi błąd, możesz ponownie przesłać to żądanie zgodnie z zdefiniowanymi przez Ciebie zasadami wycofywania. Ponowne próby wykonania żądania, które jest częścią łańcucha, oznaczają, że zostanie ono powtórnie wykonane z podawanymi danymi wejściowymi. Nie wpłynie to na żadne zadania wykonywane równolegle.

Diagram przedstawiający łańcuch zadań. Jedno z zadań zakończyło się niepowodzeniem, ale miało zdefiniowaną zasadę ponowienia. To zadanie zostanie ponownie uruchomione po upływie odpowiedniego czasu. Kolejne zadania w łańcuchu są blokowane, dopóki nie zostanie ono uruchomione.

Więcej informacji o definiowaniu niestandardowych strategii ponownych prób znajdziesz w artykule Zasady ponownych prób i zmniejszenia częstotliwości.

Jeśli zasada ponownego próbowania jest niezdefiniowana lub wyczerpana albo jeśli w jakiś inny sposób osiągniesz stan, w którym funkcja OneTimeWorkRequest zwraca wartość Result.failure(), to żądanie pracy i wszystkie zależne żądania pracy zostaną oznaczone jako FAILED..

Diagram przedstawiający łańcuch zadań. Jedno zadanie nie powiodło się i nie można go powtórzyć. W efekcie wszystkie kolejne zadania w łańcuchu również się nie udają.

Ta sama zasada obowiązuje, gdy anulujesz OneTimeWorkRequest. Wszystkie zależne prośby o wykonanie pracy są też oznaczone jako CANCELLED i nie będą wykonywane.

Diagram przedstawiający łańcuch zadań. Jedno zadanie zostało anulowane. W efekcie wszystkie zadania po nim w łańcuchu są też anulowane.

Jeśli dodasz więcej próśb o przeniesienie do łańcucha, który nie został zakończony lub został anulowany, nowo dodana prośba zostanie oznaczona odpowiednio jako FAILED lub CANCELLED. Jeśli chcesz rozszerzyć zakres obowiązywania istniejących zasad pracy, zapoznaj się z sekcją APPEND_OR_REPLACEExistingWorkPolicy.

Podczas tworzenia łańcuchów żądań pracy należy zdefiniować zasady ponownych prób, aby mieć pewność, że zadania są zawsze wykonywane w odpowiednim czasie. Nieudane żądania pracy mogą spowodować niepełne łańcuchy lub nieoczekiwany stan.

Więcej informacji znajdziesz w artykule Anulowanie i zatrzymywanie pracy.