WorkManager & Background Tasks
Reliable, battery-friendly deferrable background work on Android
WorkManager
Periodic Tasks
Constraints
Background Sync
Background Tasks Overview
WorkManager is the recommended Jetpack library for deferrable background work that must run reliably — even if the app is closed or the device restarts. It respects battery optimizations and system constraints.
User action / timer / boot
↓
WorkManager schedules job
↓
Checks constraints (network, battery, etc.)
↓
Runs Worker.doWork() in background
↓
Returns Result.success / failure / retry
API Best For Survives Reboot
WorkManager Deferrable, guaranteed work Yes
Foreground Service User-visible ongoing tasks Depends
Coroutine (in-app) Short tasks while app is open No
AlarmManager Exact-time alarms With permission
1 WorkManager Basics
WorkManager runs tasks in a Worker class. You enqueue a WorkRequest , and the system executes doWork() when conditions are met.
Gradle dependency
Kotlin — app/build.gradle.kts dependencies {
val workVersion = "2.9.0"
implementation("androidx.work:work-runtime-ktx:$workVersion")
}
Create a Worker
Kotlin — UploadWorker.kt class UploadWorker(
context: Context,
params: WorkerParameters
) : CoroutineWorker(context, params) {
override suspend fun doWork(): Result {
val filePath = inputData.getString("file_path") ?: return Result.failure()
return try {
uploadFile(filePath)
Log.d("UploadWorker", "Upload successful: $filePath")
Result.success()
} catch (e: Exception) {
Log.e("UploadWorker", "Upload failed", e)
if (runAttemptCount < 3) Result.retry() else Result.failure()
}
}
private suspend fun uploadFile(path: String) {
delay(3000) // Simulate network upload
}
}
Enqueue one-time work
Kotlin — MainActivity.kt val uploadRequest = OneTimeWorkRequestBuilder<UploadWorker>()
.setInputData(
workDataOf("file_path" to "/storage/photo.jpg")
)
.build()
WorkManager.getInstance(this).enqueue(uploadRequest)
Observe work status
Kotlin — Observe with LiveData WorkManager.getInstance(this)
.getWorkInfoByIdLiveData(uploadRequest.id)
.observe(this) { workInfo ->
when (workInfo?.state) {
WorkInfo.State.ENQUEUED -> Log.d("Work", "Queued")
WorkInfo.State.RUNNING -> Log.d("Work", "Running")
WorkInfo.State.SUCCEEDED -> Toast.makeText(this, "Upload done!", Toast.LENGTH_SHORT).show()
WorkInfo.State.FAILED -> Toast.makeText(this, "Upload failed", Toast.LENGTH_SHORT).show()
else -> {}
}
}
Worker result types
Result Meaning
Result.success()Work completed; removed from queue
Result.failure()Work failed permanently; no retry
Result.retry()Work failed temporarily; retry with backoff
2 Periodic Tasks
Periodic work repeats at a fixed interval — sync data, refresh cache, clean temp files. Minimum interval is 15 minutes on Android.
PeriodicWorker example
Kotlin — CacheCleanupWorker.kt class CacheCleanupWorker(
context: Context,
params: WorkerParameters
) : CoroutineWorker(context, params) {
override suspend fun doWork(): Result {
return try {
val cacheDir = applicationContext.cacheDir
cacheDir.listFiles()?.forEach { file ->
if (file.lastModified() < System.currentTimeMillis() - 7 * 24 * 60 * 60 * 1000L) {
file.delete()
}
}
Log.d("CacheCleanup", "Old cache files removed")
Result.success()
} catch (e: Exception) {
Result.failure()
}
}
}
Enqueue periodic work
Kotlin — Schedule every 24 hours val cleanupRequest = PeriodicWorkRequestBuilder<CacheCleanupWorker>(
24, TimeUnit.HOURS,
15, TimeUnit.MINUTES // flex interval
).build()
WorkManager.getInstance(context).enqueueUniquePeriodicWork(
"cache_cleanup",
ExistingPeriodicWorkPolicy.KEEP,
cleanupRequest
)
Unique periodic work policies
Policy Behavior
KEEPKeep existing work; ignore new request
REPLACECancel existing; enqueue new request
UPDATEUpdate existing work with new configuration
CANCEL_AND_REENQUEUECancel and re-enqueue with new config
3 Constraints
Constraints define conditions that must be met before WorkManager runs a task — network available, battery not low, device charging, etc.
Common constraints
Kotlin — Build constraints val constraints = Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED) // Any network
.setRequiresBatteryNotLow(true)
.setRequiresStorageNotLow(true)
.setRequiresCharging(false)
.build()
val syncRequest = OneTimeWorkRequestBuilder<SyncWorker>()
.setConstraints(constraints)
.build()
WorkManager.getInstance(context).enqueue(syncRequest)
NetworkType options
NetworkType Runs When
NOT_REQUIREDNo network needed (default)
CONNECTEDAny internet connection
UNMETEREDWi-Fi or unmetered connection only
NOT_ROAMINGNot on roaming network
METEREDCellular or metered Wi-Fi
Combined constraints example
Kotlin — Upload only on Wi-Fi when charging val uploadConstraints = Constraints.Builder()
.setRequiredNetworkType(NetworkType.UNMETERED)
.setRequiresCharging(true)
.build()
val uploadWork = OneTimeWorkRequestBuilder<UploadWorker>()
.setConstraints(uploadConstraints)
.setInputData(workDataOf("file_path" to photoPath))
.build()
4 Background Sync
Background sync keeps local data in step with a remote server — fetch new items, push pending changes, refresh feeds. WorkManager is ideal because sync can wait until network and battery conditions are favorable.
SyncWorker with Repository
Kotlin — SyncWorker.kt class SyncWorker(
context: Context,
params: WorkerParameters
) : CoroutineWorker(context, params) {
override suspend fun doWork(): Result {
return try {
val repository = ContactRepository(
AppDatabase.getInstance(applicationContext).contactDao()
)
// Pull remote changes
val remoteContacts = ApiService.fetchContacts()
repository.insertAll(remoteContacts)
// Push local pending changes
val pending = repository.getPendingSyncContacts()
pending.forEach { contact ->
ApiService.uploadContact(contact)
repository.markSynced(contact.id)
}
Result.success(
workDataOf("synced_count" to remoteContacts.size)
)
} catch (e: IOException) {
Log.e("SyncWorker", "Network error", e)
Result.retry()
} catch (e: Exception) {
Result.failure()
}
}
}
Schedule sync on app start and periodically
Kotlin — Application class or MainActivity fun scheduleSync(context: Context) {
val syncConstraints = Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.setRequiresBatteryNotLow(true)
.build()
// Immediate one-time sync
val immediateSync = OneTimeWorkRequestBuilder<SyncWorker>()
.setConstraints(syncConstraints)
.build()
// Periodic sync every 6 hours
val periodicSync = PeriodicWorkRequestBuilder<SyncWorker>(
6, TimeUnit.HOURS
)
.setConstraints(syncConstraints)
.build()
WorkManager.getInstance(context).apply {
enqueue(immediateSync)
enqueueUniquePeriodicWork(
"data_sync",
ExistingPeriodicWorkPolicy.KEEP,
periodicSync
)
}
}
Sync on boot with BootReceiver
Kotlin — BootReceiver.kt class BootReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent?) {
if (intent?.action == Intent.ACTION_BOOT_COMPLETED) {
scheduleSync(context) // Re-schedule periodic sync after reboot
}
}
}
5 Scheduling Tasks
WorkManager supports one-time delays, chained work, parallel tasks, and unique work names to avoid duplicates. Use these patterns to build reliable task pipelines.
Delayed one-time work
Kotlin — Run after 30 minutes val reminderWork = OneTimeWorkRequestBuilder<ReminderWorker>()
.setInitialDelay(30, TimeUnit.MINUTES)
.setInputData(workDataOf("message" to "Time to take a break!"))
.build()
WorkManager.getInstance(context).enqueue(reminderWork)
Work chain (sequential pipeline)
Kotlin — Download → Process → Upload chain val downloadWork = OneTimeWorkRequestBuilder<DownloadWorker>().build()
val processWork = OneTimeWorkRequestBuilder<ProcessWorker>().build()
val uploadWork = OneTimeWorkRequestBuilder<UploadWorker>().build()
WorkManager.getInstance(context)
.beginWith(downloadWork)
.then(processWork)
.then(uploadWork)
.enqueue()
Parallel work with combine
Kotlin — Run two tasks in parallel, then merge val syncContacts = OneTimeWorkRequestBuilder<SyncContactsWorker>().build()
val syncTasks = OneTimeWorkRequestBuilder<SyncTasksWorker>().build()
val notifyWork = OneTimeWorkRequestBuilder<NotifyWorker>().build()
WorkManager.getInstance(context)
.beginWith(listOf(syncContacts, syncTasks))
.then(notifyWork)
.enqueue()
Unique work — prevent duplicates
Kotlin — Unique one-time work WorkManager.getInstance(context).enqueueUniqueWork(
"upload_photo",
ExistingWorkPolicy.REPLACE, // Replace if already queued
uploadRequest
)
Cancel and tag work
Kotlin — Tags and cancellation val work = OneTimeWorkRequestBuilder<SyncWorker>()
.addTag("sync")
.addTag("user_data")
.build()
WorkManager.getInstance(context).enqueue(work)
// Cancel all work with tag
WorkManager.getInstance(context).cancelAllWorkByTag("sync")
// Cancel unique periodic work
WorkManager.getInstance(context).cancelUniqueWork("data_sync")
Backoff policy for retries
Kotlin — Exponential backoff on retry val retryWork = OneTimeWorkRequestBuilder<UploadWorker>()
.setBackoffCriteria(
BackoffPolicy.EXPONENTIAL,
10, TimeUnit.SECONDS
)
.build()
6 Hands-On Exercises
1
Create an UploadWorker that logs a message and returns Result.success(). Enqueue it as one-time work from a button click.
2
Observe work status with getWorkInfoByIdLiveData and show "Running" / "Done" / "Failed" in the UI.
3
Schedule a periodic task that runs every 15 minutes and logs the current timestamp.
4
Add constraints : only run sync when network is connected and battery is not low.
5
Build a SyncWorker that fetches mock data from an API and saves it to Room database.
6
Create a work chain : DownloadWorker → ProcessWorker → NotifyWorker running sequentially.
7
Bonus: Use enqueueUniquePeriodicWork with a BootReceiver to re-schedule sync after device reboot.
WorkManager & Background Tasks MCQ Practice
10 Basic MCQs
10 Advanced MCQs
10 Basic WorkManager & Background Tasks MCQs
1
WorkManager guarantees?
A Instant main thread UI
B Deferrable work runs eventually with constraints
C Replaces Activity
D SQL migrations only
Explanation: Survives reboots and Doze; respects battery optimizations.
2
Worker class extends?
A Fragment
B Activity
C Worker or CoroutineWorker
D Service only
Explanation: CoroutineWorker uses suspend doWork() for Kotlin coroutines.
3
One-time work enqueued with?
A Room insert
B startActivity
C sendBroadcast only
D WorkManager.enqueue(OneTimeWorkRequest)
Explanation: OneTimeWorkRequestBuilder creates single execution work.
4
PeriodicWorkRequest minimum interval?
A 15 minutes
B 1 second
C 1 hour only
D 1 day fixed
Explanation: Platform minimum for periodic work is 15 minutes.
5
Constraints can require?
A Only GPS always
B Network, charging, battery not low
C Only camera
D Only UI visible
Explanation: Set Constraints.Builder requirements before enqueue.
6
WorkManager survives?
A Only while Activity visible
B Nothing
C App kill and device reboot
D Gradle sync only
Explanation: WorkManager persists work across process death and reboot until completed or cancelled.
7
Unique work name used for?
A Camera capture
B Encryption
C Layout inflation
D Enqueue uniquely — REPLACE or KEEP policy
Explanation: enqueueUniqueWork prevents duplicate sync jobs.
8
doWork() should return?
A Result.success(), failure(), or retry()
B void only
C Activity intent
D SQL cursor
Explanation: Result determines retry behavior on failure.
9
WorkManager replaces for most apps?
A All UI code
B AlarmManager + JobScheduler boilerplate
C Room database
D ViewBinding
Explanation: Recommended API for background deferrable tasks.
10
Input data to Worker via?
A Manifest
B SharedPreferences only
C Data.Builder put values in WorkRequest
D Toast
Explanation: Pass primitives and strings in Data — size limited.
10 Advanced WorkManager & Background Tasks MCQs
11
CoroutineWorker vs Worker?
A Identical
B CoroutineWorker suspend doWork on background coroutine
C Worker faster always
D CoroutineWorker main thread
Explanation: Prefer CoroutineWorker for Kotlin async code.
12
Chained work?
A Manifest only
B Impossible
C beginWith(workA).then(workB).enqueue()
D Single Worker only
Explanation: WorkContinuation sequences dependent tasks.
13
Expedited work (12+)?
A Same as periodic
B Free unlimited
C Banned
D Runs faster with quota limits
Explanation: setExpedited for user-initiated urgent background work.
14
WorkInfo.State FAILED means?
A Work finished with failure result
B Still running
C Cancelled only
D Success
Explanation: Observe WorkInfo live data or Flow for status.
15
Battery not low constraint?
A Requires charging only
B Requires battery above threshold
C Requires WiFi
D Requires camera
Explanation: setRequiresBatteryNotLow(true) in Constraints.
16
Hilt Worker injection?
A Manual new only
B Impossible
C @HiltWorker + AssistedInject for DI in workers
D Manifest meta-data only
Explanation: Hilt provides WorkerFactory for dependency injection.
17
Cancel work by?
A adb reboot
B stopService only
C finish Activity
D WorkManager.cancelWorkById or cancelUniqueWork
Explanation: Cancel pending or running work when user logs out etc.
18
Retry with backoff?
A Result.retry() applies backoff policy
B Immediate infinite loop
C Crash
D ANR
Explanation: setBackoffCriteria on WorkRequest for exponential backoff.
19
WorkManager vs AlarmManager exact alarms?
A Same API
B WorkManager for flexible deferrable; AlarmManager for precise time alarms
C AlarmManager always better
D WorkManager for exact clock
Explanation: Exact alarms need SCHEDULE_EXACT_ALARM permission on 12+.
20
Testing WorkManager?
A Production only
B Cannot test
C TestDriver set all constraints met; run synchronously in tests
D Emulator banned
Explanation: androidx.work:work-testing provides TestListenableWorkerBuilder.
Check All Answers
Click an option to select, then check answers.
WorkManager & Background Tasks Interview Q&A
15 topic-focused questions for interviews and revision.
1 What is WorkManager?easy
Answer: Jetpack library scheduling guaranteed background work respecting system optimizations and constraints.
2 Create and enqueue one-time worker.easy
Answer: val req = OneTimeWorkRequestBuilder().build(); WorkManager.getInstance(ctx).enqueue(req)
3 Periodic sync every 24 hours.medium
Answer: PeriodicWorkRequestBuilder(24, TimeUnit.HOURS).setConstraints(...).build() — note 15 min minimum for short intervals.
4 Pass data to Worker.easy
Answer: OneTimeWorkRequestBuilder.from(inputData).build() where inputData built with Data.Builder.
5 Return retry on network failure.medium
Answer: doWork(): return if (success) Result.success() else Result.retry()
6 Constraints example for upload.easy
Answer: Requires network connected: Constraints.Builder().setRequiredNetworkType(CONNECTED).build()
7 WorkManager vs Foreground Service.medium
Answer: WorkManager for deferrable background; foreground service for user-visible ongoing tasks.
8 Unique work REPLACE policy.medium
Answer: enqueueUniqueWork("sync", ExistingWorkPolicy.REPLACE, request) replaces pending work with same name.
9 Observe work status.medium
Answer: WorkManager.getWorkInfoByIdLiveData(id).observe { state -> ... }
10 Chain download then process.medium
Answer: WorkManager.beginWith(downloadWork).then(processWork).enqueue()
11 Why not Thread.sleep in Worker for hours?hard
Answer: Workers should finish quickly; schedule periodic or split work; long tasks may be stopped.
12 CoroutineWorker example.medium
Answer: override suspend fun doWork(): Result = withContext(Dispatchers.IO) { api.sync(); Result.success() }
13 Cancel sync on logout.easy
Answer: WorkManager.cancelUniqueWork("user_sync")
14 WorkManager and Doze mode.hard
Answer: WorkManager batches work during Doze and runs when constraints met — respects battery.
15 Migration from IntentService.medium
Answer: Replace with CoroutineWorker or Worker; enqueue via WorkManager instead of startService.