Po zdefiniowaniuWorker
i WorkRequest
WorkRequest
WorkRequest
WorkRequest
WorkRequest
WorkRequest
WorkRequest
WorkRequest
WorkRequest
WorkRequest
WorkRequest
WorkRequest
WorkRequest
WorkRequest
WorkRequest
WorkRequest
WorkRequest
WorkRequest
WorkRequest
WorkRequest
WorkRequest
WorkRequest
WorkRequest
WorkRequest
WorkRequest
WorkRequest
WorkRequest
WorkRequest
WorkRequest
WorkRequest
WorkRequest
WorkRequest
WorkRequest
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ąć powielania. 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 dodać to samo zadanie do kolejki, 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()
do pracy jednorazowej,WorkManager.enqueueUniquePeriodicWork()
do pracy okresowej;
Obie te metody przyjmują 3 argumenty:
- uniqueWorkName –
String
używany do jednoznacznego identyfikowania prośby o wykonanie pracy. - 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 wykorzystaniu unikalnych prac 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 w kolejce jest już zadanie sendLogs, 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 łańcuch 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 poinformować WorkManager, jakie działanie ma podjąć 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, 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 jakAPPEND
, z tym że nie zależy od stanu pracy wymaganej. Jeśli istniejąca praca jestCANCELLED
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
obiektu WorkInfo
, który zawiera 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 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 na numer
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 procesu Worker
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 termin 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ą w posiadaniu procesu roboczego. 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 się zatrzymuje.
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 obiekcie Worker 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 obiekt Worker, który otrzymał sygnał onStop, ponieważ jest on już uznawany za zatrzymany.
Obserwowanie stanu przyczyny zatrzymania
Aby sprawdzić, dlaczego Worker
zostało zatrzymane, możesz zarejestrować przyczynę zatrzymania, wywołując funkcję
WorkInfo.getStopReason()
:
Kotlin
workManager.getWorkInfoByIdFlow(syncWorker.id)
.collect { workInfo ->
if (workInfo != null) {
val stopReason = workInfo.stopReason
logStopReason(syncWorker.id, stopReason)
}
}
Java
workManager.getWorkInfoByIdLiveData(syncWorker.id)
.observe(getViewLifecycleOwner(), workInfo -> {
if (workInfo != null) {
int stopReason = workInfo.getStopReason();
logStopReason(syncWorker.id, workInfo.getStopReason());
}
});