Po zdefiniowaniuWorker
i WorkRequest
ostatnim krokiem jest umieszczenie zadania w kolejce. Najprostszym sposobem dodania zadania do kolejki jest wywołanie metody enqueue()
WorkManager, przekazując 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 zadań do kolejki, aby uniknąć duplikacji. Na przykład aplikacja może próbować przesyłać dzienniki do usługi backendu co 24 godziny. Jeśli nie zachowasz ostrożności, możesz wiele razy umieścić to samo zadanie w kolejce, mimo że powinno ono zostać wykonane tylko raz. Aby to osiągnąć, możesz zaplanować pracę jako niepowtarzalną.
Unikalne dzieło
Unikalna praca to zaawansowana koncepcja, która gwarantuje, że w danym momencie masz tylko 1 instancję pracy o określonej nazwie. W odróżnieniu od identyfikatorów unikalne nazwy są czytelne dla człowieka i określane przez dewelopera, a nie generowane automatycznie przez WorkManager. W przeciwieństwie do tagów unikalne nazwy są powiązane tylko z jedną instancją pracy.
Unikalne zadania można stosować zarówno w przypadku 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ę cykliczną, czy jednorazową.
WorkManager.enqueueUniqueWork()
za jednorazową pracę,WorkManager.enqueueUniquePeriodicWork()
– praca okresowa;
Obie te metody przyjmują 3 argumenty:
- uniqueWorkName –
String
używany do jednoznacznego identyfikowania prośby o wykonanie zadania. - existingWorkPolicy –
enum
, który informuje WorkManager, co zrobić, jeśli istnieje już niedokończony łańcuch zadań o tej unikalnej nazwie. Więcej informacji znajdziesz w zasadach rozwiązywania konfliktów. - work –
WorkRequest
do zaplanowania.
Dzięki unikalnej pracy możemy rozwiązać wspomniany wcześniej problem z duplikowaniem 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);
Jeśli kod zostanie uruchomiony, gdy zadanie sendLogs jest już w kolejce, istniejące zadanie zostanie zachowane i nie zostanie dodane nowe.
Unikalne sekwencje działań mogą być też przydatne, jeśli musisz stopniowo tworzyć długi ciąg zadań. Na przykład aplikacja do edycji zdjęć może umożliwiać użytkownikom cofnięcie długiego łańcucha działań. Każda z tych operacji cofania może zająć trochę czasu, ale musi być wykonana w odpowiedniej kolejności. W takim przypadku aplikacja może utworzyć łańcuch „cofnij” i w razie potrzeby dołączać do niego poszczególne operacje cofania. Więcej informacji znajdziesz w sekcji Łączenie pracy.
Zasady rozwiązywania konfliktów
Podczas planowania unikalnej pracy musisz określić, jakie działanie ma podjąć WorkManager w przypadku konfliktu. Aby to zrobić, podczas dodawania zadania do kolejki przekaż wyliczenie.
W przypadku pracy jednorazowej podajesz ExistingWorkPolicy
, który obsługuje 4 opcje rozwiązywania konfliktu.
REPLACE
istniejące z nowymi. Ta opcja anuluje bieżącą pracę.KEEP
istniejącą pracę i zignorować nową.APPEND
nową pracę na końcu istniejącej. Ta zasada spowoduje połączenie nowego zadania z istniejącym zadaniem, które będzie wykonywane po zakończeniu istniejącego zadania.
Dotychczasowa praca staje się wymaganiem wstępnym dla nowej pracy. Jeśli istniejąca praca stanie się CANCELLED
lub FAILED
, nowa praca również będzie CANCELLED
lub FAILED
.
Jeśli chcesz, aby nowe zadanie było wykonywane niezależnie od stanu istniejącego zadania, użyj APPEND_OR_REPLACE
.
APPEND_OR_REPLACE
działa podobnie doAPPEND
, z tym że nie zależy od stanu pracy wymaganej. Jeśli istniejąca praca ma stanCANCELLED
lubFAILED
, nowa praca nadal będzie wykonywana.
W przypadku pracy okresowej podajesz wartość ExistingPeriodicWorkPolicy
, która obsługuje 2 opcje: REPLACE
i KEEP
. Te opcje działają tak samo jak ich odpowiedniki w przypadku istniejących zasad dotyczących pracy.
Obserwowanie Twojej pracy
W dowolnym momencie po dodaniu zadania do kolejki możesz sprawdzić jego 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
obiektów WorkInfo
, które zawierają id
pracy, jej tagi, bieżący State
i wszystkie zbiory danych wyjściowych korzystające z Result.success(outputData)
.
Warianty LiveData
i Flow
każdej z metod umożliwiają obserwowanie zmian w WorkInfo
przez zarejestrowanie odbiorcy. Jeśli na przykład chcesz wyświetlić użytkownikowi komunikat po pomyślnym zakończeniu jakiegoś zadania, możesz skonfigurować go w ten sposób:
Kotlin
workManager.getWorkInfoByIdFlow(syncWorker.id)
.collect{ 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();
}
});
Zapytania dotyczące złożonych zadań
WorkManager w wersji 2.4.0 i nowszych obsługuje złożone zapytania dotyczące zadań w kolejce za pomocą obiektów WorkQuery
. WorkQuery umożliwia wyszukiwanie zadań na podstawie kombinacji tagów, stanu i unikalnej nazwy zadania.
Poniższy przykład pokazuje, jak znaleźć wszystkie zadania z tagiem „syncTag”, które są w stanie FAILED
lub CANCELLED
i mają unikalną 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 WorkQuery
jest AND
-ony z pozostałymi. Każda wartość w komponencie jest OR
-ed. Na przykład: (name1 OR name2
OR ...) AND (tag1 OR tag2 OR ...) AND (state1 OR state2 OR ...)
.
WorkQuery
działa też z odpowiednikiem LiveData, getWorkInfosLiveData()
, i odpowiednikiem Flow, getWorkInfosFlow()
.
Anulowanie i zatrzymywanie pracy
Jeśli nie chcesz już, aby wcześniej dodane do kolejki zadanie zostało wykonane, możesz poprosić o jego anulowanie. Zadanie może anulować name
, id
lub tag
powiązany z tym zadaniem.
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
pracy. Jeśli zadanie jest już ukończone, nic się nie dzieje. W przeciwnym razie stan zadania zmieni się na CANCELLED
i nie będzie ono już uruchamiane. Wszystkie zadaniaWorkRequest
, które są zależne od tego zadania, również będą CANCELLED
.
RUNNING
służbowy
odbiera połączenie
ListenableWorker.onStopped()
.
Zastąp tę metodę, aby obsłużyć potencjalne czyszczenie. Więcej informacji znajdziesz w artykule Zatrzymywanie działającego procesu.
Zatrzymywanie uruchomionego pracownika
Istnieje kilka powodów, dla których WorkManager może zatrzymać działanie Worker
:
- wyraźnie poprosisz o anulowanie (np. dzwoniąc pod numer
WorkManager.cancelWorkById(UUID)
); - W przypadku unikalnej pracy wyraźnie umieszczasz w kolejce nowy element
WorkRequest
zExistingWorkPolicy
o wartościREPLACE
. Stara subskrypcjaWorkRequest
zostanie natychmiast anulowana. - Ograniczenia dotyczące Twojej pracy nie są już spełnione.
- System z jakiegoś powodu nakazał aplikacji przerwanie pracy. Może się to zdarzyć, jeśli przekroczysz czas wykonania wynoszący 10 minut. Praca zostanie zaplanowana do ponownego wykonania w późniejszym terminie.
W takich przypadkach instancja robocza zostanie zatrzymana.
Powinieneś wspólnie przerwać wszelkie trwające prace i zwolnić wszystkie zasoby, które są używane przez proces roboczy. Na przykład w tym momencie należy zamknąć otwarte uchwyty do baz danych i plików. Do dyspozycji masz 2 mechanizmy, które pozwalają sprawdzić, kiedy pracownik kończy pracę.
Wywołanie zwrotne onStopped()
WorkManager wywołuje
ListenableWorker.onStopped()
natychmiast po zatrzymaniu obiektu Worker. Zastąp tę metodę, aby zamknąć
wszystkie zasoby, które mogą być w użyciu.
Właściwość isStopped()
Możesz wywołać metodę
ListenableWorker.isStopped()
, aby sprawdzić, czy pracownik został już zatrzymany. Jeśli w procesie roboczym wykonujesz długotrwałe lub powtarzalne operacje, często sprawdzaj tę właściwość i używaj jej jako sygnału do jak najszybszego zakończenia pracy.
Uwaga: WorkManager ignoruje wartość Result
ustawioną przez proces roboczy, który otrzymał sygnał onStop, ponieważ jest on już uznawany za zatrzymany.