Background Work Boundaries

Use the smallest background mechanism that matches the user promise.

WorkUseDo Not Use
In-screen async workCoroutine in viewModelScope or repository scopeWorkManager
Reliable deferrable workWorkManagerRaw threads or one-off coroutines
Exact alarmAlarmManager, only when exact timing is truly requiredWorkManager for clock-precise promises
User-visible long-running workForeground service or long-running Worker with notificationSilent background loops
Incoming platform eventBroadcast receiver, then hand off quicklyHeavy parsing directly in receiver

WorkManager Fits

Use WorkManager when the work should survive app exit or device reboot:

  • export backup after user request
  • periodic local cleanup
  • deferred sync when network is available
  • retryable upload of user-approved diagnostics
  • post-import processing that can resume later

WorkManager gives you constraints, unique work, chaining, retries/backoff, and persistent scheduling.

WorkManager Does Not Fit

Do not use WorkManager for:

  • filtering a list while the screen is visible
  • loading initial UI state from a repository
  • parsing one SMS synchronously during onboarding
  • exact alarm-clock behavior
  • continuous background tracking with no user-visible reason

Unique Work Pattern

Use unique names for recurring or replaceable jobs:

val request = OneTimeWorkRequestBuilder<ExportBackupWorker>()
    .setConstraints(
        Constraints.Builder()
            .setRequiresBatteryNotLow(true)
            .build(),
    )
    .build()

WorkManager.getInstance(context).enqueueUniqueWork(
    "export-backup",
    ExistingWorkPolicy.REPLACE,
    request,
)

Worker Boundary

A worker should read durable state, perform one job, and return a clear result.

class ExportBackupWorker(
    context: Context,
    params: WorkerParameters,
) : CoroutineWorker(context, params) {
    override suspend fun doWork(): Result {
        return try {
            // Read from repository or database and write the export.
            Result.success()
        } catch (retryable: IOException) {
            Result.retry()
        } catch (fatal: IllegalArgumentException) {
            Result.failure()
        }
    }
}

Device Reality

WorkManager is Doze-aware and persistent, not instant. OEM battery managers can delay work more aggressively than a Pixel emulator. Test important jobs on the device class users actually own.