WorkManager basics

Background work and notifications Junior Kotlin 2.0+ API 24+ Reviewed By Best Latest Apps

Pick the fix

Every app launch enqueues a new periodic sync, and after a week the sync runs dozens of times per hour. Fix?

Options
Hint 1 of 1

How does WorkManager tell two requests are the same job?

Choose an answer, then open Show answer below to check it.

Show answer

Answer: A Use enqueueUniquePeriodicWork("sync", ExistingPeriodicWorkPolicy.KEEP, request)

Correct. One named periodic job; later enqueues keep the existing one.

Why not the others?
  • B Cancel all work on launch, then enqueue. Cancels unrelated work too, and still races.
  • C Increase the interval to 1 hour. Still duplicated, just less often.
  • D Move sync to Application.onCreate. Runs on every process start instead.

30-second answer

Use WorkManager for deferrable work that must run even if the app is closed or the device restarts: uploading logs, syncing, cleaning caches. It persists work requests in its own database, respects constraints like network or charging, retries with backoff, and picks the right system scheduler. It doesn't guarantee exact timing; the system batches work to save battery.

Practise saying it · 35 s. No recording, just a timer

Explain WorkManager.

Say your answer out loud, then check which of these points you covered:

  • Deferrable, guaranteed work
  • Persists across restarts
  • Constraints and backoff
  • Not exact timing
  • Unique work avoids duplicates

Deep dive

CoroutineWorker runs doWork() as a suspend function; return Result.success(), retry() or failure().

OneTimeWorkRequest and PeriodicWorkRequest (minimum interval 15 minutes).

enqueueUniqueWork with a policy (KEEP, REPLACE, APPEND) prevents duplicates.

Work input and output are small Data objects (about 10 KB); pass IDs, not payloads.

A sync worker Compile-checked · Kotlin 2.4.21
class SyncWorker(context: Context, params: WorkerParameters) : CoroutineWorker(context, params) {
    override suspend fun doWork(): Result = try {
        loadFeed()
        Result.success()
    } catch (e: java.io.IOException) {
        if (runAttemptCount < 3) Result.retry() else Result.failure()
    }
}

fun scheduleSync(context: Context) {
    val request = PeriodicWorkRequestBuilder<SyncWorker>(6, java.util.concurrent.TimeUnit.HOURS)
        .setConstraints(Constraints(requiredNetworkType = NetworkType.CONNECTED))
        .build()
    WorkManager.getInstance(context)
        .enqueueUniquePeriodicWork("sync", ExistingPeriodicWorkPolicy.KEEP, request)
}

Common mistakes

  • Using WorkManager for work that must run at an exact time.
  • Enqueuing the same periodic work on every app start without a unique name.
  • Passing large data through Data.

Senior take & follow-ups

State what it guarantees (eventually runs, survives reboot) and what it doesn't (exact time).

Follow-up questions

Think of your answer first, then open the hint.

  1. What's the minimum periodic interval?

    Show hint

    15 minutes.

  2. How do you avoid duplicate syncs?

    Show hint

    enqueueUniquePeriodicWork with KEEP.

Similar on iOS: Background work with BGTaskScheduler BGTaskScheduler is iOS's closest match, with much stricter limits.

Suggest a fix if something here is wrong or out of date.