Łączenie łańcuchów

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

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

Następnie za pomocą WorkContinuation możesz dodać zależne OneTimeWorkRequest instancje za pomocą then(OneTimeWorkRequest) lub then(List<OneTimeWorkRequest>) .

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

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

Przyjrzyjmy się przykładowi. W tym przykładzie skonfigurowano 3 różne zadania Worker, które mają być wykonywane (potencjalnie równolegle). Wyniki tych zadań są następnie łączone i przekazywane do zadania Worker dotyczącego buforowania. Na koniec dane wyjściowe tego zadania są przekazywane do zadania Worker dotyczącego przesyłania, które 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 instancje OneTimeWorkRequest, dane wyjściowe żądań zadań nadrzędnych są przekazywane jako dane wejściowe do zadań podrzędnych. W powyższym przykładzie dane wyjściowe plantName1, plantName2 i plantName3 zostałyby przekazane jako dane wejściowe do żądania cache.

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

WorkManager udostępnia 2 różne typy 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 połączyć dane wejściowe, tworząc w razie potrzeby tablice.

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

OverwritingInputMerger

OverwritingInputMerger to domyślna metoda łączenia. Jeśli w przypadku łączenia 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 roślin mają klucz pasujący do odpowiednich nazw zmiennych ("plantName1", "plantName2", i "plantName3"), dane przekazywane do zadania 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ść.

W przypadku konfliktu „wygrywa” ostatnie zadanie, które zostało wykonane, 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.

Ponieważ żądania zadań są wykonywane równolegle, nie masz gwarancji kolejności ich wykonywania. W powyższym przykładzie 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 przypadku łączenia, lepszym rozwiązaniem może być ArrayCreatingInputMerger.

ArrayCreatingInputMerger

W powyższym przykładzie, ponieważ chcemy zachować dane wyjściowe wszystkich zadań dotyczących nazw roślin, 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 klucz jest unikalny, wynikiem jest 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, wszystkie 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 zadań

Łańcuchy OneTimeWorkRequest są wykonywane sekwencyjnie, o ile ich zadania zostaną wykonane (czyli zwrócą Result.success()). Żądania zadań mogą się nie powieść lub zostać anulowane podczas wykonywania, co ma wpływ na zależne żądania zadań.

Gdy pierwsze OneTimeWorkRequest zostanie dodane do kolejki w łańcuchu żądań zadań, wszystkie kolejne żądania zadań zostaną zablokowane do czasu wykonania zadania pierwszego żądania.

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

Gdy pierwsze żądanie zadania zostanie dodane do kolejki i spełnione zostaną wszystkie ograniczenia zadania, zacznie się wykonywać. Jeśli zadanie zostanie wykonane w głównym OneTimeWorkRequest lub List<OneTimeWorkRequest> (czyli zwróci Result.success()), do kolejki zostanie dodany następny zestaw zależnych żądań zadań.

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

Dopóki każde żądanie zadania zostanie wykonane, ten sam wzorzec będzie się powtarzać w pozostałej części łańcucha żądań zadań, aż wszystkie zadania w łańcuchu zostaną wykonane. Jest to najprostszy i często preferowany przypadek, ale równie ważne jest obsługiwanie stanów błędów.

Gdy podczas przetwarzania żądania zadania przez worker wystąpi błąd, możesz ponowić próbę wykonania tego żądania zgodnie z zdefiniowaną przez siebie strategią wycofywania. Ponowienie próby wykonania żądania, które jest częścią łańcucha, oznacza, że ponowiona zostanie tylko próba wykonania tego żądania z przekazanymi do niego danymi wejściowymi. 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ę ponawiania. 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 prób znajdziesz w sekcji Strategia ponawiania prób i czas do ponowienia Policy.

Jeśli strategia ponawiania prób jest niezdefiniowana lub wyczerpana albo w inny sposób osiągniesz jakiś stan, w którym OneTimeWorkRequest zwraca Result.failure(), to to żądanie zadania i wszystkie zależne żądania zadań zostaną oznaczone jako FAILED.

Diagram przedstawiający łańcuch zadań. Jedno zadanie nie powiodło się i nie można go ponownie uruchomić. W rezultacie wszystkie zadania w łańcuchu, które następują po nim, również kończą się niepowodzeniem.

Ta sama logika obowiązuje, gdy OneTimeWorkRequest zostanie anulowane. Wszystkie zależne żądania zadań są również oznaczane jako CANCELLED, a ich zadania nie będą wykonywane.

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

Pamiętaj, że jeśli dodasz więcej żądań zadań do łańcucha, w którym wystąpił błąd lub który został anulowany, nowo dodane żądanie zadania również zostanie oznaczone odpowiednio jako FAILED lub CANCELLED. Jeśli chcesz rozszerzyć zadanie istniejącego łańcucha, zapoznaj się z sekcją APPEND_OR_REPLACE w ExistingWorkPolicy.

Podczas tworzenia łańcuchów żądań zadań zależne żądania zadań powinny definiować strategie ponawiania prób, aby zapewnić terminowe wykonanie zadania. Nieudane żądania zadań mogą spowodować niekompletne łańcuchy lub nieoczekiwany stan.

Więcej informacji znajdziesz w sekcji Anulowanie i zatrzymywanie zadań.