Łączenie łańcuchów

WorkManager pozwala utworzyć i umieścić w kolejce łańcuch pracy, który określa wiele zależnych zadań oraz określa 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() do enqueue() swojego łańcucha 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. Dane wyjściowe tego zadania są przekazywane do instancji roboczej przesyłania, która 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ępuje wcześniej ustawione klucze.

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

Jeśli chcesz podać bardziej szczegółowy przypadek użycia, możesz utworzyć własny, przypisując klasyfikację 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 dane wyjściowe mają różne klucze, dlatego następne zadanie otrzymuje 3 pary klucz-wartość.

Jeśli wystąpi konflikt, jako ostatni robot roboczy ukończył „wygrane”, a jego wartość jest przekazywana do funkcji 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, w jakiej kolejności będą wykonywane. W powyższym przykładzie plantName1 może zawierać wartość "tulip" lub "elm" zależnie od tego, jaka 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 ze 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();

Funkcja 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. Kolejne zadanie przekazuje 3 tablice, po 1 dla każdego klucza wyjściowego. 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 błąd wystąpi, gdy instancja robocza przetwarza Twoje żądanie robocze, możesz spróbować je wysłać ponownie zgodnie ze zdefiniowaną przez siebie zasadą ponowienia. 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 będzie to miało wpływu na współpracę prowadzoną równolegle.

Diagram przedstawiający łańcuch zadań. Jedno z zadań zakończyło się niepowodzeniem, ale zdefiniowano 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 jakimś stanie OneTimeWorkRequest zwraca wartość Result.failure(), to żądanie pracy i wszystkie zależne żądania pracy są oznaczane 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ą.

Te same zasady obowiązują w przypadku anulowania polecenia 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ń. 1 zadanie zostało anulowane. W związku z tym wszystkie kolejne zadania w łańcuchu również zostaną 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ć działanie istniejącego łańcucha, zobacz APPEND_OR_REPLACE w existingWorkPolicy.

Podczas tworzenia łańcuchów żądań pracy zależne żądania pracy powinny określać zasady ponownych prób, aby zawsze były wykonywane w odpowiednim czasie. Nieudane żądania robocze mogą skutkować niepełnymi łańcuchami lub nieoczekiwanym stanem.

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