Im Leitfaden für die ersten Schritte wurde beschrieben, wie Sie ein WorkRequest
erstellen und in die Warteschlange einreihen.
In dieser Anleitung erfahren Sie, wie Sie WorkRequest
-Objekte definieren und anpassen, um häufige Anwendungsfälle zu bearbeiten, z. B.:
- Einmalige und wiederkehrende Aufgaben planen
- Arbeitsbeschränkungen festlegen, z. B. WLAN oder Aufladen erforderlich
- Mindestverzögerung bei der Ausführung von Aufgaben garantieren
- Wiederholungs- und Backoff-Strategien festlegen
- Eingabedaten an die Arbeit übergeben
- Ähnliche Aufgaben mit Tags gruppieren
Übersicht
Arbeit wird in WorkManager mit einem WorkRequest
definiert. Wenn Sie mit WorkManager Aufgaben planen möchten, müssen Sie zuerst ein WorkRequest
-Objekt erstellen und es dann in die Warteschlange einreihen.
Kotlin
val myWorkRequest = ...
WorkManager.getInstance(myContext).enqueue(myWorkRequest)
Java
WorkRequest myWorkRequest = ...
WorkManager.getInstance(myContext).enqueue(myWorkRequest);
Das WorkRequest
-Objekt enthält alle Informationen, die WorkManager zum Planen und Ausführen Ihrer Arbeit benötigt. Sie enthält Einschränkungen, die erfüllt sein müssen, damit Ihre Arbeit ausgeführt werden kann, Planungsinformationen wie Verzögerungen oder Wiederholungsintervalle, die Konfiguration für Wiederholungsversuche und möglicherweise Eingabedaten, wenn Ihre Arbeit darauf basiert.
WorkRequest
ist eine abstrakte Basisklasse. Es gibt zwei abgeleitete Implementierungen dieser Klasse, mit denen Sie die Anfrage erstellen können: OneTimeWorkRequest
und PeriodicWorkRequest
.
Wie die Namen schon andeuten, ist OneTimeWorkRequest
nützlich für die Planung von nicht wiederkehrenden Aufgaben, während PeriodicWorkRequest
besser für die Planung von Aufgaben geeignet ist, die in einem bestimmten Intervall wiederholt werden.
Einmalige Aufgaben planen
Für einfache Aufgaben, die keine zusätzliche Konfiguration erfordern, verwenden Sie die statische Methode from
:
Kotlin
val myWorkRequest = OneTimeWorkRequest.from(MyWork::class.java)
Java
WorkRequest myWorkRequest = OneTimeWorkRequest.from(MyWork.class);
Für komplexere Aufgaben können Sie einen Builder verwenden:
Kotlin
val uploadWorkRequest: WorkRequest =
OneTimeWorkRequestBuilder<MyWork>()
// Additional configuration
.build()
Java
WorkRequest uploadWorkRequest =
new OneTimeWorkRequest.Builder(MyWork.class)
// Additional configuration
.build();
Express-Jobs planen
Mit WorkManager 2.7.0 wurde das Konzept der Express-Jobs eingeführt. So kann WorkManager wichtige Aufgaben ausführen und das System hat eine bessere Kontrolle über den Zugriff auf Ressourcen.
Express-Jobs zeichnen sich durch die folgenden Merkmale aus:
- Wichtigkeit: Beschleunigte Arbeit eignet sich für Aufgaben, die für den Nutzer wichtig sind oder vom Nutzer initiiert werden.
- Geschwindigkeit: Die beschleunigte Bearbeitung eignet sich am besten für kurze Aufgaben, die sofort gestartet und innerhalb weniger Minuten abgeschlossen werden.
- Kontingente: Ein Kontingent auf Systemebene, das die Ausführungszeit im Vordergrund begrenzt, bestimmt, ob ein beschleunigter Job gestartet werden kann.
- Energieverwaltung: Einschränkungen der Energieverwaltung wie der Energiesparmodus und der Inaktivmodus wirken sich weniger wahrscheinlich auf beschleunigte Arbeit aus.
- Latenz: Das System führt beschleunigte Aufgaben sofort aus, sofern die aktuelle Arbeitslast des Systems dies zulässt. Das bedeutet, dass sie latenzempfindlich sind und nicht für eine spätere Ausführung geplant werden können.
Ein möglicher Anwendungsfall für die beschleunigte Verarbeitung ist eine Chat-App, in der der Nutzer eine Nachricht oder ein angehängtes Bild senden möchte. Ebenso kann es sinnvoll sein, beschleunigte Arbeit für eine App zu verwenden, die einen Zahlungs- oder Aboablauf verarbeitet. Das liegt daran, dass diese Aufgaben für den Nutzer wichtig sind, schnell im Hintergrund ausgeführt werden, sofort gestartet werden müssen und auch dann weiter ausgeführt werden sollen, wenn der Nutzer die App schließt.
Kontingente
Das System muss einem beschleunigten Job Ausführungszeit zuweisen, bevor er ausgeführt werden kann. Die Ausführungszeit ist nicht unbegrenzt. Stattdessen erhält jede App ein Kontingent an Ausführungszeit. Wenn Ihre App ihre Ausführungszeit nutzt und ihr zugewiesenes Kontingent erreicht, können Sie beschleunigte Aufgaben erst wieder ausführen, wenn das Kontingent aktualisiert wird. So kann Android Ressourcen effektiver zwischen Anwendungen aufteilen.
Die einer App zur Verfügung stehende Ausführungszeit hängt vom Standby-Bucket und der Prozesswichtigkeit ab.
Sie können festlegen, was passiert, wenn das Ausführungskontingent nicht zulässt, dass ein beschleunigter Job sofort ausgeführt wird. Weitere Informationen finden Sie in den folgenden Snippets.
Express-Job ausführen
Ab WorkManager 2.7 kann Ihre App setExpedited()
aufrufen, um zu deklarieren, dass ein WorkRequest
so schnell wie möglich als beschleunigter Job ausgeführt werden soll. Das folgende Code-Snippet zeigt ein Beispiel für die Verwendung von setExpedited()
:
Kotlin
val request = OneTimeWorkRequestBuilder<SyncWorker>()
<b>.setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)</b>
.build()
WorkManager.getInstance(context)
.enqueue(request)
Java
OneTimeWorkRequest request = new OneTimeWorkRequestBuilder<T>()
.setInputData(inputData)
<b>.setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)</b>
.build();
In diesem Beispiel initialisieren wir eine Instanz von OneTimeWorkRequest
und rufen setExpedited()
dafür auf. Diese Anfrage wird dann beschleunigt bearbeitet. Wenn das Kontingent es zulässt, wird die Ausführung sofort im Hintergrund gestartet. Wenn das Kontingent aufgebraucht ist, gibt der Parameter OutOfQuotaPolicy
an, dass die Anfrage als normaler, nicht beschleunigter Vorgang ausgeführt werden soll.
Abwärtskompatibilität und Dienste im Vordergrund
Um die Abwärtskompatibilität für beschleunigte Jobs aufrechtzuerhalten, führt WorkManager auf Plattformversionen vor Android 12 möglicherweise einen Vordergrunddienst aus. Vordergrunddienste können dem Nutzer eine Benachrichtigung anzeigen.
Mit den Methoden getForegroundInfoAsync()
und getForegroundInfo()
in Ihrem Worker kann WorkManager eine Benachrichtigung anzeigen, wenn Sie setExpedited()
vor Android 12 aufrufen.
Jede ListenableWorker
muss die Methode getForegroundInfo
implementieren, wenn Sie anfordern möchten, dass die Aufgabe als beschleunigter Job ausgeführt wird.
Wenn Sie auf Android 12 oder höher ausgerichtet sind, sind Dienste im Vordergrund weiterhin über die entsprechende setForeground
-Methode verfügbar.
Worker
Die Worker wissen nicht, ob die Arbeit, die sie erledigen, beschleunigt wird oder nicht. Worker können jedoch auf einigen Android-Versionen eine Benachrichtigung anzeigen, wenn eine WorkRequest
beschleunigt wurde.
Dazu stellt WorkManager die Methode getForegroundInfoAsync()
bereit, die Sie implementieren müssen, damit WorkManager bei Bedarf eine Benachrichtigung zum Starten eines ForegroundService
anzeigen kann.
CoroutineWorker
Wenn Sie eine CoroutineWorker
verwenden, müssen Sie getForegroundInfo()
implementieren. Anschließend übergeben Sie sie an setForeground()
in doWork()
. Dadurch wird die Benachrichtigung in Android-Versionen vor Version 12 erstellt.
Dazu ein Beispiel:
class ExpeditedWorker(appContext: Context, workerParams: WorkerParameters):
CoroutineWorker(appContext, workerParams) {
override suspend fun getForegroundInfo(): ForegroundInfo {
return ForegroundInfo(
NOTIFICATION_ID, createNotification()
)
}
override suspend fun doWork(): Result {
TODO()
}
private fun createNotification() : Notification {
TODO()
}
}
Kontingentrichtlinien
Sie können festlegen, was mit beschleunigten Aufgaben passiert, wenn das Ausführungskontingent Ihrer App erreicht ist. Um fortzufahren, können Sie setExpedited()
bestehen:
OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST
, wodurch der Job als normale Arbeitsanfrage ausgeführt wird. Das oben gezeigte Snippet veranschaulicht dies.OutOfQuotaPolicy.DROP_WORK_REQUEST
. Dadurch wird die Anfrage abgebrochen, wenn nicht genügend Kontingent vorhanden ist.
Verschobene Express-Jobs
Das System versucht, einen bestimmten beschleunigten Job so schnell wie möglich nach dem Aufrufen des Jobs auszuführen. Wie bei anderen Arten von Jobs kann das System den Start neuer beschleunigter Arbeiten jedoch verzögern, z. B. in den folgenden Fällen:
- Load: Die Systemlast ist zu hoch. Das kann passieren, wenn bereits zu viele Jobs ausgeführt werden oder wenn das System nicht genügend Arbeitsspeicher hat.
- Kontingent: Das Kontingentlimit für beschleunigte Jobs wurde überschritten. Für beschleunigte Arbeit wird ein Kontingentsystem verwendet, das auf den App-Standby-Buckets basiert und die maximale Ausführungszeit in einem fortlaufenden Zeitfenster begrenzt. Die Kontingente für beschleunigte Aufgaben sind restriktiver als die für andere Arten von Hintergrundjobs.
Regelmäßige Aufgaben planen
Manchmal muss Ihre App bestimmte Aufgaben regelmäßig ausführen. Sie möchten beispielsweise Ihre Daten regelmäßig sichern, neue Inhalte in Ihrer App herunterladen oder Protokolle auf einen Server hochladen.
So verwenden Sie PeriodicWorkRequest
, um ein WorkRequest
-Objekt zu erstellen, das regelmäßig ausgeführt wird:
Kotlin
val saveRequest =
PeriodicWorkRequestBuilder<SaveImageToFileWorker>(1, TimeUnit.HOURS)
// Additional configuration
.build()
Java
PeriodicWorkRequest saveRequest =
new PeriodicWorkRequest.Builder(SaveImageToFileWorker.class, 1, TimeUnit.HOURS)
// Constraints
.build();
In diesem Beispiel wird die Arbeit in einem einstündigen Intervall geplant.
Das Intervall wird als Mindestzeit zwischen Wiederholungen definiert. Der genaue Zeitpunkt der Ausführung des Worker hängt von den Einschränkungen ab, die Sie in Ihrem WorkRequest-Objekt verwenden, und von den Optimierungen, die vom System vorgenommen werden.
Flexible Laufintervalle
Wenn die Art Ihrer Arbeit die Ausführungszeit beeinflusst, können Sie Ihre PeriodicWorkRequest
so konfigurieren, dass sie innerhalb eines flexiblen Zeitraums in jedem Intervall ausgeführt wird (siehe Abbildung 1).
Abbildung 1: Das Diagramm zeigt sich wiederholende Intervalle mit dem flexiblen Zeitraum, in dem die Arbeit ausgeführt werden kann.
Wenn Sie periodische Arbeit mit einem flexiblen Zeitraum definieren möchten, übergeben Sie beim Erstellen des PeriodicWorkRequest
ein flexInterval
zusammen mit dem repeatInterval
. Der flexible Zeitraum beginnt um repeatInterval - flexInterval
und endet am Ende des Intervalls.
Im Folgenden sehen Sie ein Beispiel für regelmäßige Aufgaben, die in den letzten 15 Minuten jeder Stunde ausgeführt werden können.
Kotlin
val myUploadWork = PeriodicWorkRequestBuilder<SaveImageToFileWorker>(
1, TimeUnit.HOURS, // repeatInterval (the period cycle)
15, TimeUnit.MINUTES) // flexInterval
.build()
Java
WorkRequest saveRequest =
new PeriodicWorkRequest.Builder(SaveImageToFileWorker.class,
1, TimeUnit.HOURS,
15, TimeUnit.MINUTES)
.build();
Das Wiederholungsintervall muss größer oder gleich PeriodicWorkRequest.MIN_PERIODIC_INTERVAL_MILLIS
und das flexible Intervall muss größer oder gleich PeriodicWorkRequest.MIN_PERIODIC_FLEX_MILLIS` sein.
Auswirkungen von Einschränkungen auf periodische Aufgaben
Sie können Einschränkungen auf periodische Arbeiten anwenden. Sie können beispielsweise eine Einschränkung für Ihre Arbeitsanfrage hinzufügen, sodass die Arbeit nur ausgeführt wird, wenn das Gerät des Nutzers aufgeladen wird. In diesem Fall wird PeriodicWorkRequest
erst ausgeführt, wenn diese Bedingung erfüllt ist, auch wenn das definierte Wiederholungsintervall abgelaufen ist. Dies kann dazu führen, dass ein bestimmter Lauf Ihrer Arbeit verzögert oder sogar übersprungen wird, wenn die Bedingungen nicht innerhalb des Laufintervalls erfüllt werden.
Arbeitseinschränkungen
Constraints
sorgt dafür, dass die Arbeit aufgeschoben wird, bis die optimalen Bedingungen erfüllt sind. Für WorkManager sind die folgenden Einschränkungen verfügbar:
NetworkType | Beschränkt den Netzwerktyp, der für die Ausführung Ihrer Arbeit erforderlich ist.
Zum Beispiel WLAN (UNMETERED ).
|
BatteryNotLow | Wenn diese Option auf „true“ gesetzt ist, wird Ihr Arbeitsablauf nicht ausgeführt, wenn sich das Gerät im Energiesparmodus befindet. |
RequiresCharging | Wenn diese Option auf „true“ gesetzt ist, wird Ihr Arbeitsablauf nur ausgeführt, wenn das Gerät aufgeladen wird. |
DeviceIdle | Wenn diese Option auf „true“ gesetzt ist, muss das Gerät des Nutzers inaktiv sein, bevor der Vorgang ausgeführt wird. Das kann nützlich sein, um Batchvorgänge auszuführen, die sich ansonsten negativ auf die Leistung anderer Apps auswirken könnten, die aktiv auf dem Gerät des Nutzers ausgeführt werden. |
StorageNotLow | Wenn diese Option auf „true“ gesetzt ist, wird Ihr Work nicht ausgeführt, wenn der Speicherplatz des Nutzers auf dem Gerät zu gering ist. |
Wenn Sie eine Reihe von Einschränkungen erstellen und mit einer Aufgabe verknüpfen möchten, erstellen Sie eine Constraints
-Instanz mit Constraints.Builder()
und weisen Sie sie Ihrem WorkRequest.Builder()
zu.
Mit dem folgenden Code wird beispielsweise eine Arbeitsanfrage erstellt, die nur ausgeführt wird, wenn das Gerät des Nutzers sowohl aufgeladen als auch mit einem WLAN verbunden ist:
Kotlin
val constraints = Constraints.Builder()
.setRequiredNetworkType(NetworkType.UNMETERED)
.setRequiresCharging(true)
.build()
val myWorkRequest: WorkRequest =
OneTimeWorkRequestBuilder<MyWork>()
.setConstraints(constraints)
.build()
Java
Constraints constraints = new Constraints.Builder()
.setRequiredNetworkType(NetworkType.UNMETERED)
.setRequiresCharging(true)
.build();
WorkRequest myWorkRequest =
new OneTimeWorkRequest.Builder(MyWork.class)
.setConstraints(constraints)
.build();
Wenn mehrere Einschränkungen angegeben sind, wird Ihr Job nur ausgeführt, wenn alle Einschränkungen erfüllt sind.
Wenn eine Einschränkung während der Ausführung Ihrer Arbeit nicht mehr erfüllt wird, beendet WorkManager den Worker. Die Arbeit wird dann wiederholt, wenn alle Einschränkungen erfüllt sind.
Verzögerte Arbeit
Wenn Ihre Arbeit keine Einschränkungen hat oder alle Einschränkungen erfüllt sind, wenn Ihre Arbeit in die Warteschlange gestellt wird, kann das System die Arbeit sofort ausführen. Wenn Sie nicht möchten, dass die Arbeit sofort ausgeführt wird, können Sie festlegen, dass sie erst nach einer Mindestverzögerung beginnt.
Hier ist ein Beispiel dafür, wie Sie festlegen, dass Ihr Job mindestens 10 Minuten nach dem Eintreffen in der Warteschlange ausgeführt wird.
Kotlin
val myWorkRequest = OneTimeWorkRequestBuilder<MyWork>()
.setInitialDelay(10, TimeUnit.MINUTES)
.build()
Java
WorkRequest myWorkRequest =
new OneTimeWorkRequest.Builder(MyWork.class)
.setInitialDelay(10, TimeUnit.MINUTES)
.build();
Im Beispiel wird gezeigt, wie Sie eine anfängliche Verzögerung für eine OneTimeWorkRequest
festlegen. Sie können aber auch eine anfängliche Verzögerung für eine PeriodicWorkRequest
festlegen. In diesem Fall würde sich nur die erste Ausführung Ihrer periodischen Arbeit verzögern.
Richtlinie für Wiederholungsversuche und Backoff
Wenn WorkManager die Arbeit noch einmal versuchen soll, können Sie Result.retry()
aus dem Worker zurückgeben. Die Arbeit wird dann gemäß einer Backoff-Verzögerung und Backoff-Richtlinie neu geplant.
Mit Backoff-Verzögerung wird die Mindestwartezeit festgelegt, die nach dem ersten Versuch eingehalten werden muss, bevor die Arbeit wiederholt wird. Dieser Wert darf nicht weniger als 10 Sekunden (oder MIN_BACKOFF_MILLIS) betragen.
Die Backoff-Richtlinie definiert, wie sich die Backoff-Verzögerung im Laufe der Zeit für nachfolgende Wiederholungsversuche erhöhen soll. WorkManager unterstützt zwei Backoff-Richtlinien:
LINEAR
undEXPONENTIAL
.
Jede Arbeitsanfrage hat eine Backoff-Richtlinie und eine Backoff-Verzögerung. Die Standardrichtlinie ist EXPONENTIAL
mit einer Verzögerung von 30 Sekunden. Sie können diese Einstellung jedoch in der Konfiguration Ihrer Arbeitsanfrage überschreiben.
Hier ist ein Beispiel für die Anpassung der Backoff-Verzögerung und -Richtlinie.
Kotlin
val myWorkRequest = OneTimeWorkRequestBuilder<MyWork>()
.setBackoffCriteria(
BackoffPolicy.LINEAR,
OneTimeWorkRequest.MIN_BACKOFF_MILLIS,
TimeUnit.MILLISECONDS)
.build()
Java
WorkRequest myWorkRequest =
new OneTimeWorkRequest.Builder(MyWork.class)
.setBackoffCriteria(
BackoffPolicy.LINEAR,
OneTimeWorkRequest.MIN_BACKOFF_MILLIS,
TimeUnit.MILLISECONDS)
.build();
In diesem Beispiel ist die minimale Backoff-Verzögerung auf den zulässigen Mindestwert von 10 Sekunden festgelegt. Da die Richtlinie LINEAR
ist, erhöht sich das Wiederholungsintervall mit jedem neuen Versuch um etwa 10 Sekunden. Wenn beispielsweise der erste Lauf mit Result.retry()
endet, wird er nach 10 Sekunden noch einmal versucht. Wenn die Arbeit auch bei nachfolgenden Versuchen Result.retry()
zurückgibt, wird sie nach 20, 30, 40 Sekunden usw. noch einmal versucht. Wenn die Backoff-Richtlinie auf EXPONENTIAL
festgelegt wäre, läge die Sequenz der Wiederholungsdauern näher an 20, 40 und 80.
Arbeiten taggen
Jede Arbeitsanfrage hat eine eindeutige Kennung, mit der die Arbeit später identifiziert werden kann, um sie abzubrechen oder ihren Fortschritt zu beobachten.
Wenn Sie eine Gruppe von logisch zusammenhängenden Aufgaben haben, kann es auch hilfreich sein, diese Aufgaben zu taggen. Mit Tags können Sie eine Gruppe von Arbeitsanfragen gemeinsam bearbeiten.
Mit WorkManager.cancelAllWorkByTag(String)
werden beispielsweise alle Arbeitsanfragen mit einem bestimmten Tag abgebrochen und mit WorkManager.getWorkInfosByTag(String)
wird eine Liste der WorkInfo-Objekte zurückgegeben, mit denen der aktuelle Arbeitsstatus ermittelt werden kann.
Der folgende Code zeigt, wie Sie Ihrer Arbeit das Tag „cleanup“ hinzufügen können:
Kotlin
val myWorkRequest = OneTimeWorkRequestBuilder<MyWork>()
.addTag("cleanup")
.build()
Java
WorkRequest myWorkRequest =
new OneTimeWorkRequest.Builder(MyWork.class)
.addTag("cleanup")
.build();
Außerdem können einem einzelnen Arbeitsauftrag mehrere Tags hinzugefügt werden. Intern werden diese Tags als eine Reihe von Strings gespeichert. Mit WorkInfo.getTags()
können Sie die mit WorkRequest
verknüpften Tags abrufen.
In Ihrer Worker
-Klasse können Sie die zugehörigen Tags mit ListenableWorker.getTags() abrufen.
Eingabedaten zuweisen
Für Ihre Arbeit sind möglicherweise Eingabedaten erforderlich. Für eine Aufgabe, bei der ein Bild hochgeladen wird, ist beispielsweise möglicherweise der URI des hochzuladenden Bilds als Eingabe erforderlich.
Eingabewerte werden als Schlüssel/Wert-Paare in einem Data
-Objekt gespeichert und können für die Arbeitsanfrage festgelegt werden. WorkManager stellt die Eingabe Data
für Ihre Work bereit, wenn sie ausgeführt wird. Die Worker
-Klasse kann auf die Eingabeargumente zugreifen, indem sie Worker.getInputData()
aufruft. Der folgende Code zeigt, wie Sie eine Worker
-Instanz erstellen, für die Eingabedaten erforderlich sind, und wie Sie sie in Ihrer Arbeitsanfrage senden.
Kotlin
// Define the Worker requiring input
class UploadWork(appContext: Context, workerParams: WorkerParameters)
: Worker(appContext, workerParams) {
override fun doWork(): Result {
val imageUriInput =
inputData.getString("IMAGE_URI") ?: return Result.failure()
uploadFile(imageUriInput)
return Result.success()
}
...
}
// Create a WorkRequest for your Worker and sending it input
val myUploadWork = OneTimeWorkRequestBuilder<UploadWork>()
.setInputData(workDataOf(
"IMAGE_URI" to "http://..."
))
.build()
Java
// Define the Worker requiring input
public class UploadWork extends Worker {
public UploadWork(Context appContext, WorkerParameters workerParams) {
super(appContext, workerParams);
}
@NonNull
@Override
public Result doWork() {
String imageUriInput = getInputData().getString("IMAGE_URI");
if(imageUriInput == null) {
return Result.failure();
}
uploadFile(imageUriInput);
return Result.success();
}
...
}
// Create a WorkRequest for your Worker and sending it input
WorkRequest myUploadWork =
new OneTimeWorkRequest.Builder(UploadWork.class)
.setInputData(
new Data.Builder()
.putString("IMAGE_URI", "http://...")
.build()
)
.build();
Ebenso kann die Klasse Data
verwendet werden, um einen Rückgabewert auszugeben. Eingabe- und Ausgabedaten werden im Abschnitt Eingabeparameter und zurückgegebene Werte näher beschrieben.
Nächste Schritte
Auf der Seite Status und Beobachtung erfahren Sie mehr über die Arbeitsstatus und wie Sie den Fortschritt Ihrer Arbeit im Blick behalten können.