Nachdem Sie Ihre Worker
und Ihre WorkRequest
definiert haben, besteht der letzte Schritt darin, Ihre Arbeit in die Warteschlange zu stellen. Die einfachste Möglichkeit, Aufgaben in die Warteschlange zu stellen, besteht darin, die enqueue()
-Methode von WorkManager aufzurufen und die WorkRequest
zu übergeben, die ausgeführt werden soll.
Kotlin
val myWork: WorkRequest = // ... OneTime or PeriodicWork
WorkManager.getInstance(requireContext()).enqueue(myWork)
Java
WorkRequest myWork = // ... OneTime or PeriodicWork
WorkManager.getInstance(requireContext()).enqueue(myWork);
Seien Sie vorsichtig, wenn Sie Aufgaben in die Warteschlange stellen, um Duplikate zu vermeiden. Eine App kann beispielsweise versuchen, ihre Protokolle alle 24 Stunden in einen Back-End-Dienst hochzuladen. Wenn Sie nicht aufpassen, kann es passieren, dass Sie dieselbe Aufgabe mehrmals in die Warteschlange stellen, obwohl der Job nur einmal ausgeführt werden muss. Um dieses Ziel zu erreichen, können Sie die Arbeit als einmalige Arbeit planen.
Einzigartige Arbeit
Eindeutige Arbeit ist ein leistungsstarkes Konzept, das dafür sorgt, dass Sie jeweils nur eine Instanz von Arbeit mit einem bestimmten Namen haben. Im Gegensatz zu IDs sind eindeutige Namen für Menschen lesbar und werden vom Entwickler angegeben, anstatt von WorkManager automatisch generiert zu werden. Im Gegensatz zu Tags sind eindeutige Namen nur mit einer einzelnen Arbeitsinstanz verknüpft.
Einmalige Arbeit kann sowohl auf einmalige als auch auf wiederkehrende Arbeit angewendet werden. Sie können eine eindeutige Arbeitssequenz erstellen, indem Sie eine dieser Methoden aufrufen. Das hängt davon ab, ob Sie wiederholte oder einmalige Aufgaben planen.
WorkManager.enqueueUniqueWork()
für einmalige ArbeitWorkManager.enqueueUniquePeriodicWork()
für regelmäßige Arbeiten
Beide Methoden akzeptieren drei Argumente:
- uniqueWorkName: Eine
String
, die zur eindeutigen Identifizierung der Arbeitsanfrage verwendet wird. - existingWorkPolicy: Eine
enum
, die WorkManager anweist, was zu tun ist, wenn bereits eine unfertige Arbeitskette mit diesem eindeutigen Namen vorhanden ist. Weitere Informationen finden Sie in der Richtlinie zur Konfliktlösung. - work: die zu planende
WorkRequest
.
Mit eindeutigen Arbeitsvorgängen können wir das zuvor erwähnte Problem mit der doppelten Terminierung beheben.
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);
Wenn der Code jetzt ausgeführt wird, während sich bereits ein „sendLogs“-Job in der Warteschlange befindet, wird der vorhandene Job beibehalten und kein neuer Job hinzugefügt.
Eindeutige Arbeitsabfolgen können auch nützlich sein, wenn Sie eine lange Kette von Aufgaben schrittweise aufbauen müssen. In einer Bildbearbeitungs-App können Nutzer beispielsweise eine lange Kette von Aktionen rückgängig machen. Jeder dieser Rückgängig-Vorgänge kann eine Weile dauern, muss aber in der richtigen Reihenfolge ausgeführt werden. In diesem Fall könnte die App eine „Rückgängig“-Kette erstellen und bei Bedarf jeden Rückgängig-Vorgang an die Kette anhängen. Weitere Informationen finden Sie unter Arbeit verketten.
Richtlinie zur Konfliktlösung
Wenn Sie eindeutige Arbeitsvorgänge planen, müssen Sie WorkManager mitteilen, welche Aktion bei einem Konflikt ausgeführt werden soll. Dazu übergeben Sie beim Einreihen der Arbeit eine Enumeration.
Für einmalige Aufgaben geben Sie ein ExistingWorkPolicy
an, das vier Optionen für den Umgang mit dem Konflikt unterstützt.
REPLACE
vorhandene Arbeit mit der neuen Arbeit. Mit dieser Option wird die vorhandene Arbeit abgebrochen.KEEP
vorhandene Arbeit und ignoriere die neue Arbeit.APPEND
die neue Arbeit an das Ende der vorhandenen Arbeit. Durch diese Richtlinie wird Ihr neuer Job verkettet und nach Abschluss des bestehenden Jobs ausgeführt.
Die vorhandene Arbeit wird zur Voraussetzung für die neue Arbeit. Wenn die vorhandene Arbeit CANCELLED
oder FAILED
wird, ist auch die neue Arbeit CANCELLED
oder FAILED
.
Wenn die neue Aufgabe unabhängig vom Status der vorhandenen Aufgabe ausgeführt werden soll, verwenden Sie stattdessen APPEND_OR_REPLACE
.
APPEND_OR_REPLACE
funktioniert ähnlich wieAPPEND
, ist aber nicht vom Arbeitsstatus der Voraussetzung abhängig. Wenn die vorhandene ArbeitCANCELLED
oderFAILED
ist, wird die neue Arbeit trotzdem ausgeführt.
Für die Arbeit im Zeitraum geben Sie ein ExistingPeriodicWorkPolicy
an, das die beiden Optionen REPLACE
und KEEP
unterstützt. Diese Optionen funktionieren genauso wie die entsprechenden Optionen für die Arbeitsrichtlinie.
Ihre Arbeit beobachten
Nachdem Sie Arbeit in die Warteschlange gestellt haben, können Sie ihren Status jederzeit abrufen, indem Sie WorkManager anhand der name
, id
oder einer zugehörigen tag
abfragen.
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>>
Die Abfrage gibt ein ListenableFuture
eines WorkInfo
-Objekts zurück, das die id
des Werks, seine Tags, seinen aktuellen State
und alle Ausgabedatasets mit Result.success(outputData)
enthält.
Mit den Varianten LiveData
und Flow
der einzelnen Methoden können Sie Änderungen an der WorkInfo
beobachten, indem Sie einen Listener registrieren. Wenn Sie dem Nutzer beispielsweise eine Nachricht anzeigen möchten, wenn eine Aufgabe erfolgreich abgeschlossen wurde, können Sie das so einrichten:
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();
}
});
Komplexe Arbeitsanfragen
WorkManager 2.4.0 und höher unterstützt komplexe Abfragen für in die Warteschlange eingereihte Jobs mit WorkQuery
-Objekten. Mit WorkQuery können Sie nach Arbeitsvorgängen suchen, indem Sie eine Kombination aus Tags, Status und eindeutigem Namen des Arbeitsvorgangs angeben.
Das folgende Beispiel zeigt, wie Sie alle Arbeiten mit dem Tag syncTag finden, die den Status FAILED
oder CANCELLED
haben und deren Arbeitsname entweder „preProcess“ oder „sync“ ist.
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);
Jede Komponente (Tag, Status oder Name) in einem WorkQuery
wird mit den anderen AND
-ed. Jeder Wert in einer Komponente wird OR
. Beispiel: (name1 OR name2
OR ...) AND (tag1 OR tag2 OR ...) AND (state1 OR state2 OR ...)
.
WorkQuery
funktioniert auch mit dem LiveData-Äquivalent getWorkInfosLiveData()
und dem Flow-Äquivalent getWorkInfosFlow()
.
Arbeit abbrechen und beenden
Wenn Sie nicht mehr möchten, dass die zuvor in die Warteschlange gestellten Aufgaben ausgeführt werden, können Sie sie abbrechen. Arbeiten können von ihrem name
, id
oder einem zugehörigen tag
abgebrochen werden.
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");
Im Hintergrund prüft WorkManager die State
der Work. Wenn die Arbeit bereits abgeschlossen ist, passiert nichts. Andernfalls wird der Status der Arbeit zu CANCELLED
geändert und die Arbeit wird in Zukunft nicht mehr ausgeführt. Alle WorkRequest
-Jobs, die von dieser Arbeit abhängig sind, werden ebenfalls CANCELLED
.
RUNNING
(Arbeit) erhält einen Anruf an ListenableWorker.onStopped()
.
Überschreiben Sie diese Methode, um eine mögliche Bereinigung durchzuführen. Weitere Informationen finden Sie unter Aktiven Worker beenden.
Laufenden Worker beenden
Es gibt mehrere Gründe, warum dein Worker
möglicherweise von WorkManager beendet wird:
- Sie haben explizit darum gebeten, dass die Bestellung storniert wird (z. B. durch Aufrufen von
WorkManager.cancelWorkById(UUID)
). - Bei einzigartiger Arbeit haben Sie explizit einen neuen
WorkRequest
mit einemExistingWorkPolicy
vonREPLACE
in die Warteschlange gestellt. Das alteWorkRequest
wird sofort als gekündigt betrachtet. - Die Einschränkungen für Ihre Arbeit werden nicht mehr erfüllt.
- Das System hat Ihre App aus irgendeinem Grund angewiesen, die Arbeit zu beenden. Das kann passieren, wenn Sie die Ausführungsfrist von 10 Minuten überschreiten. Die Arbeit wird zu einem späteren Zeitpunkt wiederholt.
Unter diesen Bedingungen wird Ihr Worker beendet.
Sie sollten alle laufenden Arbeiten abbrechen und alle Ressourcen freigeben, die Ihr Worker belegt. Schließen Sie beispielsweise offene Handles für Datenbanken und Dateien. Es gibt zwei Mechanismen, mit denen Sie herausfinden können, wann Ihr Worker beendet wird.
onStopped()-Callback
WorkManager ruft ListenableWorker.onStopped()
auf, sobald Ihr Worker beendet wurde. Überschreiben Sie diese Methode, um alle Ressourcen zu schließen, die Sie möglicherweise verwenden.
isStopped()-Property
Sie können die Methode ListenableWorker.isStopped()
aufrufen, um zu prüfen, ob Ihr Worker bereits beendet wurde. Wenn Sie in Ihrem Worker lang andauernde oder sich wiederholende Vorgänge ausführen, sollten Sie diese Eigenschaft regelmäßig prüfen und sie als Signal verwenden, um die Arbeit so schnell wie möglich zu beenden.
Hinweis:WorkManager ignoriert die von einem Worker festgelegte Result
, der das onStop-Signal erhalten hat, da der Worker bereits als beendet gilt.
Status des Stoppgrunds beobachten
Wenn Sie herausfinden möchten, warum ein Worker
beendet wurde, können Sie den Grund für das Beenden protokollieren, indem Sie WorkInfo.getStopReason()
aufrufen:
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());
}
});