WorkManager – Arbeit, die auch läuft, wenn die App zu ist
Daten hochladen, nachts synchronisieren, eine Erinnerung schicken: Sobald etwas laufen soll, während die App geschlossen ist, ist WorkManager das richtige Werkzeug – und nicht ein Thread, den das System sowieso abräumt.
Eine Frage, die in fast jedem App-Projekt kommt: „Kann die App im Hintergrund automatisch synchronisieren?" Die Antwort ist ja — aber nicht mit einer Coroutine, die man beim Schließen der App einfach weiterlaufen lässt. Android beendet den Prozess, sobald es Speicher braucht, und dann ist die Arbeit weg.
WorkManager ist der offizielle Weg für Arbeit, die garantiert irgendwann erledigt wird, auch über einen Neustart des Geräts hinweg.
Ein Worker
class SyncWorker(
ctx: Context,
params: WorkerParameters
) : CoroutineWorker(ctx, params) {
override suspend fun doWork(): Result {
return try {
val anzahl = repository.syncPending() // ganz normale suspend-Funktion
Result.success(workDataOf("anzahl" to anzahl))
} catch (e: IOException) {
Result.retry() // Netz weg → später nochmal, mit Backoff
} catch (e: Exception) {
Result.failure() // wird nicht besser → aufgeben
}
}
}Der Unterschied zwischen retry() und failure() ist der eigentliche Kern. retry() heißt „das war Pech" — WorkManager versucht es später erneut und wartet dabei jedes Mal länger. failure() heißt „das ist kaputt" — nicht nochmal probieren. Wer beides verwechselt, bekommt entweder Endlosschleifen oder verlorene Daten.
Einmalig anstoßen – mit Bedingungen
val bedingungen = Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.setRequiresBatteryNotLow(true)
.build()
val anfrage = OneTimeWorkRequestBuilder<SyncWorker>()
.setConstraints(bedingungen)
.setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 30, TimeUnit.SECONDS)
.build()
WorkManager.getInstance(context).enqueue(anfrage)Die Constraints sind der angenehmste Teil: Du beschreibst, wann die Arbeit sinnvoll ist, und musst dich nicht selbst darum kümmern. Kein Netz? WorkManager wartet. Akku fast leer? Wartet auch.
Regelmäßig wiederholen
val taeglich = PeriodicWorkRequestBuilder<SyncWorker>(6, TimeUnit.HOURS)
.setConstraints(bedingungen)
.build()
WorkManager.getInstance(context).enqueueUniquePeriodicWork(
"sync",
ExistingPeriodicWorkPolicy.KEEP, // schon geplant? dann nicht doppelt anlegen
taeglich
)Zwei Fallen hier:
- Das Minimum sind 15 Minuten. Kürzere Intervalle akzeptiert das System nicht, und das ist gut so.
- Die Zeit ist nie exakt. Android bündelt solche Aufträge, um den Akku zu schonen. „Alle 6 Stunden" heißt „ungefähr alle 6 Stunden". Wenn etwas auf die Minute genau passieren muss, ist WorkManager das falsche Werkzeug — dann brauchst du einen
AlarmManagermit exaktem Alarm und einen guten Grund dafür.
Den Fortschritt in der UI anzeigen
val status by WorkManager.getInstance(context)
.getWorkInfosForUniqueWorkLiveData("sync")
.observeAsState()
when (status?.firstOrNull()?.state) {
WorkInfo.State.RUNNING -> CircularProgressIndicator()
WorkInfo.State.SUCCEEDED -> Text("Alles synchronisiert ✓")
else -> {}
}Meine Faustregel
Sobald die Frage lautet „läuft das auch, wenn die App zu ist?", ist die Antwort WorkManager. Alles, was nur läuft, solange der Nutzer hinschaut, gehört dagegen in eine Coroutine im ViewModel — dort ist WorkManager unnötiger Ballast.
Du überlegst, ob dein App-Projekt so eine Synchronisation braucht? Melde dich, ich sage dir ehrlich, ob sich der Aufwand lohnt.
Quellen
Du brauchst mehr als ein Snippet?
Ich entwickle Android-Apps in Kotlin und moderne Websites für Selbstständige und kleine Unternehmen — von der ersten Idee bis zum Release.
Projekt anfragen →Verwandte Snippets
kotlinx.serialization: JSON und data class ohne Handarbeit verbinden
Eine API antwortet mit JSON, deine App will eine data class. Dazwischen steht in vielen Projekten ein handgeschriebener Parser. Mit kotlinx.serialization sind es eine Annotation und eine Zeile – und ein Schalter, ohne den deine App beim nächsten API-Update abstürzt.
callbackFlow – Listener-APIs in einen Flow verwandeln
Android steckt voller Callback-APIs mit `register`/`unregister`. Mit `callbackFlow` machst du daraus einen ganz normalen Flow – inklusive automatischem Abmelden, wenn niemand mehr zuhört.
AnimatedVisibility in Jetpack Compose – ein- und ausblenden, das nicht springt
Ein Element einfach mit if wegzulassen, poppt hart weg. AnimatedVisibility blendet es weich ein und aus – mit sinnvollen Voreinstellungen und, wenn du willst, deiner eigenen Kombination aus Faden und Bewegung. Ich zeige dir beides.