Po zdefiniowaniu Worker
i WorkRequest
musisz umieścić swoją pracę w kolejce. Najprostszym sposobem umieszczania pracy w kolejce jest wywołanie metody enqueue()
w usłudze WorkManager i przekazanie zdarzenia WorkRequest
, które chcesz uruchomić.
Kotlin
val myWork: WorkRequest = // ... OneTime or PeriodicWork WorkManager.getInstance(requireContext()).enqueue(myWork)
Java
WorkRequest myWork = // ... OneTime or PeriodicWork WorkManager.getInstance(requireContext()).enqueue(myWork);
Zachowaj ostrożność podczas dodawania pracy do kolejki, aby uniknąć powielenia. Aplikacja może na przykład próbować przesyłać logi do usługi backendu co 24 godziny. Jeśli nie zachowasz ostrożności, możesz wielokrotnie umieścić to samo zadanie w kolejce, mimo że wystarczy je uruchomić tylko raz. Aby osiągnąć ten cel, możesz zaplanować wykonywanie pracy jako niepowtarzalne zadanie.
Unikalne dzieło
Unikalne treści to zaawansowana koncepcja, która gwarantuje, że w danym momencie masz tylko jedno wystąpienie pracy o konkretnej nazwie. W przeciwieństwie do identyfikatorów unikalne nazwy są zrozumiałe dla człowieka i określane przez programistę, a nie są generowane automatycznie przez WorkManager. W przeciwieństwie do tagów unikalne nazwy są powiązane tylko z jednym wystąpieniem zadania.
Unikalne treści można wykorzystać zarówno do pracy jednorazowej, jak i okresowej. Możesz utworzyć unikalną sekwencję pracy, wywołując jedną z tych metod w zależności od tego, czy planujesz pracę powtarzalną czy jednorazową.
WorkManager.enqueueUniqueWork()
za jednorazową pracęWorkManager.enqueueUniquePeriodicWork()
za okresowe czynności
W obu przypadkach mogą być używane 3 argumenty:
- uniqueWorkName –
String
używany do jednoznacznej identyfikacji żądania roboczego. - existingWorkPolicy –
enum
, który informuje WorkManager o tym, co zrobić, gdy istnieje już niedokończony łańcuch zadań o tej unikalnej nazwie. Więcej informacji znajdziesz w zasadach dotyczących rozwiązywania konfliktów. - work –
WorkRequest
do zaplanowania.
Wykorzystując unikalne nakłady pracy, możemy rozwiązać wspomniany wcześniej problem z ustalaniem harmonogramu.
Kotlin
val sendLogsWorkRequest = PeriodicWorkRequestBuilder<SendLogsWorker>(24, TimeUnit.HOURS) .setConstraints(Constraints.Builder() .setRequiresCharging(true) .build() ) .build() WorkManager.getInstance(this).enqueueUniquePeriodicWork( "sendLogs", ExistingPeriodicWorkPolicy.KEEP, sendLogsWorkRequest )
Java
PeriodicWorkRequest sendLogsWorkRequest = new PeriodicWorkRequest.Builder(SendLogsWorker.class, 24, TimeUnit.HOURS) .setConstraints(new Constraints.Builder() .setRequiresCharging(true) .build() ) .build(); WorkManager.getInstance(this).enqueueUniquePeriodicWork( "sendLogs", ExistingPeriodicWorkPolicy.KEEP, sendLogsWorkRequest);
Teraz, jeśli kod zostanie uruchomiony, gdy zadanie sendLogs jest już w kolejce, istniejące zadanie zostanie zachowane i nie zostanie dodane żadne nowe zadanie.
Unikalne sekwencje zadań mogą być też przydatne, jeśli musisz stopniowo tworzyć długi łańcuch zadań. Na przykład aplikacja do edycji zdjęć może pozwalać użytkownikom na cofanie wielu czynności. Cofanie tych operacji może trochę potrwać, ale trzeba je wykonywać we właściwej kolejności. W tym przypadku aplikacja może utworzyć łańcuch cofania i w razie potrzeby dołączać do łańcucha każdą operację cofania. Więcej informacji znajdziesz w sekcji Praca łańcuchów.
Zasady rozwiązywania konfliktów
Planując unikalne zadania, musisz poinformować zespół WorkManager, co ma zrobić, gdy wystąpi konflikt. W tym celu należy przekazać zadanie w kolejce.
W przypadku zadań jednorazowych podajesz właściwość ExistingWorkPolicy
, która obsługuje 4 opcje rozwiązywania konfliktu.
REPLACE
praca z nową pracą. Ta opcja anuluje istniejące zadanie.KEEP
istniejący utwór i zignoruj nowy.APPEND
nową pracę do końca istniejącego. Ta zasada powoduje, że nowa praca jest powiązana z istniejącym zadaniem po jego zakończeniu.
Istniejące utwory staje się warunkem wstępnym nowego. Jeśli istniejące zadanie to CANCELLED
lub FAILED
, nowy utwór też jest CANCELLED
lub FAILED
.
Jeśli chcesz, aby nowa praca była wykonywana niezależnie od stanu istniejącego, użyj zamiast tego polecenia APPEND_OR_REPLACE
.
APPEND_OR_REPLACE
działa podobnie doAPPEND
z tą różnicą, że nie jest zależne od stanu zadania wstępnego. Jeśli dotychczasowe zadanie toCANCELLED
lubFAILED
, nowa wersja wciąż działa.
W przypadku okresu próbnego podajesz wartość ExistingPeriodicWorkPolicy
, która obsługuje 2 opcje: REPLACE
i KEEP
. Te opcje działają tak samo jak ich odpowiedniki IstniejąceWorkPolicy.
Obserwowanie pracy
W każdej chwili po dodaniu zadań do kolejki możesz sprawdzić ich stan, wysyłając zapytanie do WorkManagera za pomocą name
, id
lub powiązanego z nim tag
.
Kotlin
// by id workManager.getWorkInfoById(syncWorker.id) // ListenableFuture<WorkInfo> // by name workManager.getWorkInfosForUniqueWork("sync") // ListenableFuture<List<WorkInfo>> // by tag workManager.getWorkInfosByTag("syncTag") // ListenableFuture<List<WorkInfo>>
Java
// by id workManager.getWorkInfoById(syncWorker.id); // ListenableFuture<WorkInfo> // by name workManager.getWorkInfosForUniqueWork("sync"); // ListenableFuture<List<WorkInfo>> // by tag workManager.getWorkInfosByTag("syncTag"); // ListenableFuture<List<WorkInfo>>
Zapytanie zwraca ListenableFuture
obiektu WorkInfo
, który zawiera id
utworu, jego tagi, aktualny State
oraz wszelkie dane wyjściowe zbioru za pomocą funkcji Result.success(outputData)
.
Wariant LiveData
każdej z metod umożliwia obserwację zmian w elemencie WorkInfo
przez zarejestrowanie odbiornika. Jeśli na przykład chcesz, by po pomyślnym zakończeniu jakiejś pracy wyświetlała się wiadomość, możesz ją skonfigurować w ten sposób:
Kotlin
workManager.getWorkInfoByIdLiveData(syncWorker.id) .observe(viewLifecycleOwner) { workInfo -> if(workInfo?.state == WorkInfo.State.SUCCEEDED) { Snackbar.make(requireView(), R.string.work_completed, Snackbar.LENGTH_SHORT) .show() } }
Java
workManager.getWorkInfoByIdLiveData(syncWorker.id) .observe(getViewLifecycleOwner(), workInfo -> { if (workInfo.getState() != null && workInfo.getState() == WorkInfo.State.SUCCEEDED) { Snackbar.make(requireView(), R.string.work_completed, Snackbar.LENGTH_SHORT) .show(); } });
Złożone zapytania dotyczące pracy
WorkManager w wersji 2.4.0 i nowszych obsługuje złożone zapytania dotyczące zadań umieszczonych w kolejce przy użyciu obiektów WorkQuery
. WorkQuery obsługuje zapytania służbowe z uwzględnieniem tagów, stanu i unikalnej nazwy pracy.
Poniższy przykład pokazuje, jak znaleźć wszystkie operacje z tagiem “syncTag”, które ma stan FAILED
lub CANCELLED
i ma niepowtarzalną nazwę „preProcess” lub „sync”.
Kotlin
val workQuery = WorkQuery.Builder .fromTags(listOf("syncTag")) .addStates(listOf(WorkInfo.State.FAILED, WorkInfo.State.CANCELLED)) .addUniqueWorkNames(listOf("preProcess", "sync") ) .build() val workInfos: ListenableFuture<List<WorkInfo>> = workManager.getWorkInfos(workQuery)
Java
WorkQuery workQuery = WorkQuery.Builder .fromTags(Arrays.asList("syncTag")) .addStates(Arrays.asList(WorkInfo.State.FAILED, WorkInfo.State.CANCELLED)) .addUniqueWorkNames(Arrays.asList("preProcess", "sync") ) .build(); ListenableFuture<List<WorkInfo>> workInfos = workManager.getWorkInfos(workQuery);
Każdy komponent (tag, stan lub nazwa) w elemencie WorkQuery
jest łączony z innymi komponentami (AND
). Każda wartość w komponencie jest zakodowana za pomocą OR
, np. (name1 OR name2
OR ...) AND (tag1 OR tag2 OR ...) AND (state1 OR state2 OR ...)
.
WorkQuery
działa też z odpowiednikiem LiveData getWorkInfosLiveData()
.
Anulowanie i zatrzymywanie pracy
Jeśli nie potrzebujesz już pracy umieszczonej w kolejce do wykonania, możesz poprosić o jej anulowanie. Dzieło może zostać anulowane przez name
, id
lub powiązaną z nim tag
.
Kotlin
// by id workManager.cancelWorkById(syncWorker.id) // by name workManager.cancelUniqueWork("sync") // by tag workManager.cancelAllWorkByTag("syncTag")
Java
// by id workManager.cancelWorkById(syncWorker.id); // by name workManager.cancelUniqueWork("sync"); // by tag workManager.cancelAllWorkByTag("syncTag");
WorkManager sprawdza State
zadania. Jeśli praca jest już zakończona, nic się nie dzieje. W przeciwnym razie stan utworu zmienia się na CANCELLED
i utwór nie będzie kontynuowany. Wszystkie zadania WorkRequest
zależne od tych zadań również będą miały stan CANCELLED
.
Obecnie RUNNING
zadanie odbiera wywołanie ListenableWorker.onStopped()
.
Aby móc wykonywać ewentualne operacje czyszczenia, zastąp tę metodę. Więcej informacji znajdziesz w artykule o zatrzymywaniu uruchomionej instancji roboczej.
Zatrzymywanie uruchomionej instancji roboczej
Aplikacja WorkManager może zatrzymać uruchamianie pliku Worker
z kilku różnych powodów:
- Otrzymaliśmy od Ciebie wyraźną prośbę o jego anulowanie (np. przez wywołanie
WorkManager.cancelWorkById(UUID)
). - W przypadku niepowtarzalnego utworu został przez Ciebie jawnie umieszczony w kolejce nowy element
WorkRequest
z wartościąExistingWorkPolicy
o wartościREPLACE
. StaryWorkRequest
zostanie natychmiast uznany za anulowany. - Ograniczenia dotyczące Twojej pracy nie są już spełnione.
- System z jakiegoś powodu uznał, że aplikacja ma zatrzymać pracę. Może się tak zdarzyć, jeśli przekroczysz termin wykonania wynoszący 10 minut. Ponowne wykonanie zadania zaplanowano na później.
W tych warunkach instancja robocza jest zatrzymana.
Wspólnie przerwijcie wszystkie trwające prace i zwolnij wszystkie zasoby, których ma instancja robocza. Na przykład należy zamknąć uchwyty do bazy danych i plików. Masz do dyspozycji 2 mechanizmy pozwalające dowiedzieć się, kiedy serwer roboczy się zatrzymuje.
onStopped()
WorkManager wywołuje ListenableWorker.onStopped()
, gdy tylko instancja robocza zostanie zatrzymana. Zastąp tę metodę, aby zamknąć wszystkie zasoby.
właściwość isStopped()
Możesz wywołać metodę ListenableWorker.isStopped()
, aby sprawdzić, czy instancja robocza została już zatrzymana. Jeśli w swojej instancji roboczej wykonujesz długotrwałe lub powtarzające się operacje, często sprawdzaj tę właściwość i używaj jej jako sygnału do jak najszybszego zatrzymania pracy.
Uwaga: WorkManager ignoruje Result
ustawiony przez instancję roboczą, która otrzymała sygnał onStop, ponieważ instancja robocza jest już uznawana za zatrzymaną.