Łączenie łańcuchów

WorkManager umożliwia tworzenie i umieszczanie w kolejce łańcucha zadań, który określa wiele zależnych zadań i definiuje kolejność ich wykonywania. Ta funkcja jest szczególnie przydatna, gdy musisz wykonać kilka zadań w określonej kolejności.

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

Za pomocą znaku WorkContinuation można dodawać zależne instancje OneTimeWorkRequest, używając then(OneTimeWorkRequest) lub then(List<OneTimeWorkRequest>).

Każde wywołanie funkcji WorkContinuation.then(...) zwraca nową instancję funkcji WorkContinuation. Jeśli dodasz List instancji OneTimeWorkRequest, te żądania mogą być wykonywane równolegle.

Na koniec możesz użyć metody WorkContinuation.enqueue() do enqueue() łańcucha WorkContinuation.

Przeanalizujmy przykład. W tym przykładzie skonfigurowano 3 różne zadania Worker, które mają być wykonywane (potencjalnie równolegle). Wyniki tych instancji roboczych są następnie łączone i przekazywane do zadania instancji roboczej buforowania. Na koniec dane wyjściowe tego zadania są przekazywane do procesu przesyłania, który przesyła wyniki na serwer zdalny.

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

Łączenie danych wejściowych

Gdy połączysz ze sobą instancje OneTimeWorkRequest, dane wyjściowe żądań pracy nadrzędnej są przekazywane jako dane wejściowe do elementów podrzędnych. W przykładzie powyżej dane wyjściowe funkcji plantName1, plantName2plantName3 zostaną przekazane jako dane wejściowe do żądania cache.

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

WorkManager udostępnia 2 rodzaje InputMerger:

  • OverwritingInputMerger próbuje dodać wszystkie klucze ze wszystkich wejść do wyjścia. W przypadku konfliktu zastępuje wcześniej ustawione klucze.

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

Jeśli masz bardziej konkretny przypadek użycia, możesz napisać własną klasę, tworząc podklasę klasy InputMerger.

OverwritingInputMerger

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

Jeśli na przykład dane wejściowe każdego zakładu mają klucz pasujący do odpowiedniej nazwy zmiennej ("plantName1", "plantName2""plantName3"), dane przekazywane do instancji roboczej cache będą zawierać 3 pary klucz-wartość.

Diagram przedstawiający 3 zadania przekazujące różne dane wyjściowe do następnego zadania w łańcuchu. Ponieważ wszystkie 3 dane wyjściowe mają różne klucze, następne zadanie otrzymuje 3 pary klucz/wartość.

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

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

Żądania pracy są wykonywane równolegle, więc nie masz gwarancji kolejności ich wykonywania. W powyższym przykładzie zmienna plantName1 może mieć wartość "tulip" lub "elm" w zależności od tego, która wartość zostanie zapisana jako ostatnia. Jeśli istnieje ryzyko konfliktu kluczy i musisz zachować wszystkie dane wyjściowe w procesie łączenia, lepszym rozwiązaniem może być ArrayCreatingInputMerger.

ArrayCreatingInputMerger

W powyższym przykładzie, ponieważ chcemy zachować dane wyjściowe wszystkich instancji roboczych plant name, powinniśmy użyć znaku 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 przypisuje do każdego klucza tablicę. Jeśli każdy z kluczy jest niepowtarzalny, wynikiem będzie seria tablic jednoelementowych.

Diagram przedstawiający 3 zadania przekazujące różne dane wyjściowe do następnego zadania w łańcuchu. Następne zadanie otrzymuje 3 tablice, po jednej dla każdego klucza wyjściowego. Każda tablica ma jednego członka.

Jeśli wystąpią kolizje kluczy, odpowiednie wartości zostaną zgrupowane w tablicy.

Diagram przedstawiający 3 zadania przekazujące dane wyjściowe do następnego zadania w łańcuchu. W tym przypadku 2 z tych zadań generują dane wyjściowe z tym samym kluczem. Następne zadanie otrzymuje 2 tablice, po jednej dla każdego klucza. Jedna z tych tablic ma 2 elementy, ponieważ były 2 dane wyjściowe z tym kluczem.

Łączenie i stany pracy

Łańcuchy OneTimeWorkRequest są wykonywane sekwencyjnie, o ile ich działanie zakończy się pomyślnie (czyli zwrócą wartość Result.success()). Żądania pracy mogą zakończyć się niepowodzeniem lub zostać anulowane podczas wykonywania, co ma wpływ na zależne żądania pracy.

Gdy w łańcuchu żądań pracy zostanie umieszczone pierwsze żądanie OneTimeWorkRequest, wszystkie kolejne żądania pracy są blokowane do czasu zakończenia pracy tego pierwszego żądania.

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

Po dodaniu do kolejki i spełnieniu wszystkich ograniczeń dotyczących pracy rozpoczyna się wykonywanie pierwszego żądania pracy. Jeśli praca zostanie wykonana w OneTimeWorkRequest lub List<OneTimeWorkRequest> (czyli zwróci Result.success()), zostanie umieszczony w kolejce następny zestaw zależnych żądań pracy.

Diagram przedstawiający łańcuch zadań. Pierwsze zadanie zostało wykonane, a jego 2 bezpośrednie następniki zostały umieszczone w kolejce. Pozostałe zadania są blokowane do czasu zakończenia poprzednich zadań.

Jeśli każde żądanie pracy zostanie zrealizowane, ten sam wzorzec będzie propagowany przez pozostałą część łańcucha żądań pracy, dopóki wszystkie zadania w łańcuchu nie zostaną wykonane. Chociaż jest to najprostszy i często preferowany przypadek, równie ważne jest obsługiwanie stanów błędów.

Jeśli podczas przetwarzania Twojego żądania przez pracownika wystąpi błąd, możesz ponowić to żądanie zgodnie z określonymi przez siebie zasadami wycofywania. Ponawianie żądania, które jest częścią łańcucha, oznacza, że tylko to żądanie zostanie ponowione z danymi wejściowymi, które zostały mu przekazane. Nie wpłynie to na żadne zadania wykonywane równolegle.

Diagram przedstawiający łańcuch zadań. Jedno z zadań nie powiodło się, ale miała zdefiniowaną zasadę wycofywania. Zostanie ono ponownie uruchomione po upływie odpowiedniego czasu. Zadania w łańcuchu, które następują po nim, są blokowane do czasu jego pomyślnego wykonania.

Więcej informacji o definiowaniu niestandardowych strategii ponawiania znajdziesz w zasadach ponawiania i wycofywania.

Jeśli zasady ponawiania są niezdefiniowane lub wyczerpane albo osiągniesz stan, w którym OneTimeWorkRequest zwraca 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 ponownie uruchomić. W rezultacie nie powiodą się też wszystkie zadania w łańcuchu, które następują po nim.

Ta sama logika obowiązuje w przypadku anulowania OneTimeWorkRequest. Wszystkie zależne prośby o wykonanie pracy są również oznaczone symbolem CANCELLED i nie będą realizowane.

Diagram przedstawiający łańcuch zadań. 1 zadanie zostało anulowane. W rezultacie wszystkie zadania w łańcuchu, które następują po nim, również zostaną anulowane.

Pamiętaj, że jeśli dodasz kolejne prośby o wykonanie pracy do łańcucha, w którym wystąpił błąd lub w którym anulowano prośby o wykonanie pracy, nowo dodane prośby o wykonanie pracy również zostaną oznaczone odpowiednio symbolem FAILED lub CANCELLED. Jeśli chcesz rozszerzyć zakres prac w ramach istniejącego łańcucha, zapoznaj się z sekcją APPEND_OR_REPLACEExistingWorkPolicy.

Podczas tworzenia łańcuchów żądań pracy zależne żądania pracy powinny definiować zasady ponawiania, aby zapewnić terminowe wykonanie pracy. Nieudane żądania pracy mogą powodować niekompletne łańcuchy lub nieoczekiwany stan.

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