Background Work with WorkManager
WorkManager runs deferrable, guaranteed background work — syncs, uploads, periodic cleanup — that should survive app exit and device restart.
WorkManager is shown here as idiomatic code. It needs the Android runtime to execute, so it is not part of the CI unit-test module.
Setup
implementation("androidx.work:work-runtime-ktx:2.9.1")
A CoroutineWorker
CoroutineWorker lets you write suspending work directly:
class SyncWorker(
context: Context,
params: WorkerParameters,
) : CoroutineWorker(context, params) {
override suspend fun doWork(): Result = try {
// suspend work — e.g. repository.sync()
Result.success()
} catch (e: Exception) {
Result.retry()
}
}
Return Result.success(), Result.retry(), or Result.failure().
Constraints
Only run when conditions are met (network, charging, idle):
val constraints = Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.setRequiresCharging(true)
.build()
Scheduling
// one-off
val request = OneTimeWorkRequestBuilder<SyncWorker>()
.setConstraints(constraints)
.build()
WorkManager.getInstance(context).enqueue(request)
// periodic (minimum interval 15 minutes)
val periodic = PeriodicWorkRequestBuilder<SyncWorker>(1, TimeUnit.HOURS).build()
WorkManager.getInstance(context).enqueueUniquePeriodicWork(
"sync", ExistingPeriodicWorkPolicy.KEEP, periodic,
)
Observing work state
WorkManager.getInstance(context)
.getWorkInfoByIdFlow(request.id)
.collect { info -> /* RUNNING, SUCCEEDED, FAILED ... */ }
When to use what
| Need | Use |
|---|---|
| Deferrable, guaranteed work | WorkManager |
| Immediate work tied to the UI | viewModelScope coroutine |
| Exact-time alarms | AlarmManager |
Exercises
-
Write a
CoroutineWorkerthat “uploads” (simulated) and returnsretryon failure. -
Schedule it to run only when the device is on an unmetered network.
Previous: Dependency Injection with Hilt · Next: Modularization & Build Variants