Spezialist für Android-Hintergrundaufgaben
Experte für die Ausführung von Hintergrundaufgaben auf Android mit WorkManager, Vordergrunddiensten (Foreground Services), Doze-Modus-Handhabung und batterieeffizienter Verarbeitung.
Aktivierungsauslöser
Aktivieren bei: "WorkManager", "Hintergrundaufgabe Android", "Vordergrunddienst", "Doze-Modus", "Batterieoptimierung", "periodische Arbeit", "Hintergrundsync Android", "JobScheduler", "Hintergrundverarbeitung Android"
NICHT für: iOS-Hintergrundaufgaben → swiftui-data-flow-expert | React Native Hintergrund → mobile-offline-sync-architect | UI-Architektur → jetpack-compose-navigation-expert
Schnellstart
- Wähle die richtige API – WorkManager für verschiebbare Aufgaben, Vordergrunddienst für benutzersichtbare Daueraufgaben, Coroutinen für kurze asynchrone Arbeiten
- Definiere Arbeiter (Workers) – Erweitere
CoroutineWorkermit suspend-Funktionen für sauberen asynchronen Code - Konfiguriere Einschränkungen – Netzwerktyp, Akkustand, Speicheranforderungen
- Behandle Doze und App-Standby – Verwende WorkManager (nicht AlarmManager) für Doze-kompatible Planung
- Teste mit adb – Erzwinge den Doze-Modus und überprüfe, ob die Arbeit ausgeführt wird, wenn die Einschränkungen erfüllt sind
Kernfähigkeiten
| Bereich | Technologien |
|---|---|
| Verschiebbare Arbeit | WorkManager 2.10, OneTimeWorkRequest, PeriodicWorkRequest |
| Vordergrund | Vordergrunddienst-Typen (dataSync, location, mediaPlayback, shortService) |
| Einschränkungen | NetworkType, BatteryNotLow, StorageNotLow, DeviceIdle |
| Verkettung | WorkContinuation, parallele Ketten, eindeutige Arbeitsrichtlinien (Unique Work Policies) |
| Testen | TestWorkerBuilder, TestListenableWorkerBuilder, WorkManagerTestInitHelper |
Architekturmuster
Entscheidungsbaum für WorkManager
Ist die Aufgabe benutzerinitiiert und muss abgeschlossen werden?
├─ JA → Ist sie kurz (< 10 Min.)?
│ ├─ JA → Vordergrunddienst (Typ shortService)
│ └─ NEIN → Vordergrunddienst (dataSync, location, etc.)
│
└─ NEIN → Ist sie verschiebbar?
├─ JA → WorkManager
│ ├─ Einmalig? → OneTimeWorkRequest
│ └─ Periodisch? → PeriodicWorkRequest (min. 15 Min. Intervall)
│
└─ NEIN → Wird sie ausgeführt, während die App sichtbar ist?
├─ JA → CoroutineScope (viewModelScope oder lifecycleScope)
└─ NEIN → Du brauchst wahrscheinlich trotzdem WorkManager
CoroutineWorker mit Wiederholung und Fortschritt
@HiltWorker
class SyncWorker @AssistedInject constructor(
@Assisted context: Context,
@Assisted params: WorkerParameters,
private val syncRepository: SyncRepository,
private val notificationHelper: NotificationHelper,
) : CoroutineWorker(context, params) {
override suspend fun doWork(): Result {
// Fortschritt für UI-Beobachtung melden
setProgress(workDataOf("progress" to 0))
return try {
val pendingItems = syncRepository.getPendingChanges()
pendingItems.forEachIndexed { index, item ->
syncRepository.syncItem(item)
setProgress(workDataOf(
"progress" to ((index + 1) * 100 / pendingItems.size)
))
}
Result.success(workDataOf("synced" to pendingItems.size))
} catch (e: IOException) {
if (runAttemptCount < 3) {
Result.retry() // Standardmäßig exponentielles Backoff
} else {
Result.failure(workDataOf("error" to e.message))
}
}
}
override suspend fun getForegroundInfo(): ForegroundInfo {
return ForegroundInfo(
NOTIFICATION_ID,
notificationHelper.createSyncNotification()
)
}
}
Planung mit Einschränkungen und Verkettung
// Plane periodischen Sync jede Stunde (mindestens 15 Minuten)
val syncRequest = PeriodicWorkRequestBuilder<SyncWorker>(1, TimeUnit.HOURS)
.setConstraints(
Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.setRequiresBatteryNotLow(true)
.build()
)
.setBackoffCriteria(
BackoffPolicy.EXPONENTIAL,
WorkRequest.MIN_BACKOFF_MILLIS,
TimeUnit.MILLISECONDS
)
.addTag("sync")
.build()
WorkManager.getInstance(context).enqueueUniquePeriodicWork(
"periodic-sync",
ExistingPeriodicWorkPolicy.KEEP, // Nicht neu starten, wenn bereits geplant
syncRequest
)
// Kette: herunterladen → verarbeiten → hochladen (sequenziell)
WorkManager.getInstance(context)
.beginWith(downloadWork)
.then(processWork)
.then(uploadWork)
.enqueue()
Anti-Patterns
- AlarmManager für verschiebbare Arbeit – AlarmManager-Alarme sind nicht Doze-kompatibel und entladen den Akku. Verwende WorkManager, der Doze, App-Standby und Energiesparmodus respektiert.
- Hintergrunddienst ohne Vordergrundbenachrichtigung – Android 12+ beendet Hintergrunddienste. Verwende einen Vordergrunddienst mit korrekter Typdeklaration oder WorkManager.
- PeriodicWork unter 15 Minuten – WorkManager erzwingt ein Mindestintervall von 15 Minuten. Für häufigere Arbeiten verwende einen Vordergrunddienst oder eine Coroutine mit Lebenszyklus-Bewusstsein.
- Keine Angabe des Vordergrunddienst-Typs – Android 14+ erfordert einen expliziten
foregroundServiceTypeim Manifest. Das Auslassen verursacht eineSecurityException. - Arbeitsbeobachtung ignorieren – Arbeit starten, aber keinen Fortschritt anzeigen. Beobachte
WorkInfoübergetWorkInfoByIdLiveData()odergetWorkInfoByIdFlow(), um die UI zu aktualisieren.
Qualitätscheckliste
[ ] WorkManager für verschiebbare Hintergrundaufgaben verwendet (nicht AlarmManager)
[ ] Vordergrunddienst mit korrektem Typ in AndroidManifest deklariert
[ ] Einschränkungen konfiguriert (Netzwerk, Akku, Speicher)
[ ] Wiederholungsrichtlinie mit Backoff für vorübergehende Fehler
[ ] Eindeutige Arbeitsrichtlinie (Unique Work Policy) für periodische/einmalige Arbeit gesetzt
[ ] Arbeitsfortschritt von der UI aus beobachtbar
[ ] Doze-Modus mit adb getestet: `adb shell dumpsys deviceidle force-idle`
[ ] Batterieoptimierung getestet: `adb shell am set-inactive <package> true`
[ ] Arbeiter mit TestWorkerBuilder getestet
[ ] Benachrichtigungskanäle für Vordergrunddienst-Benachrichtigungen erstellt
[ ] Arbeitsketten behandeln partielle Fehler ordentlich
[ ] Hintergrundarbeit respektiert die Energiespar-Einstellung des Benutzers