WorkManager & Background Tasks

Reliable, battery-friendly deferrable background work on Android

WorkManager Periodic Tasks Constraints Background Sync

Table of Contents

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
APIBest ForSurvives Reboot
WorkManagerDeferrable, guaranteed workYes
Foreground ServiceUser-visible ongoing tasksDepends
Coroutine (in-app)Short tasks while app is openNo
AlarmManagerExact-time alarmsWith permission

1WorkManager 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.ktsdependencies { val workVersion = "2.9.0" implementation("androidx.work:work-runtime-ktx:$workVersion") }

Create a Worker

Kotlin — UploadWorker.ktclass 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.ktval uploadRequest = OneTimeWorkRequestBuilder<UploadWorker>() .setInputData( workDataOf("file_path" to "/storage/photo.jpg") ) .build() WorkManager.getInstance(this).enqueue(uploadRequest)

Observe work status

Kotlin — Observe with LiveDataWorkManager.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

ResultMeaning
Result.success()Work completed; removed from queue
Result.failure()Work failed permanently; no retry
Result.retry()Work failed temporarily; retry with backoff

2Periodic 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.ktclass 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 hoursval 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

PolicyBehavior
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

3Constraints

Constraints define conditions that must be met before WorkManager runs a task — network available, battery not low, device charging, etc.

Common constraints

Kotlin — Build constraintsval 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

NetworkTypeRuns 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 chargingval uploadConstraints = Constraints.Builder() .setRequiredNetworkType(NetworkType.UNMETERED) .setRequiresCharging(true) .build() val uploadWork = OneTimeWorkRequestBuilder<UploadWorker>() .setConstraints(uploadConstraints) .setInputData(workDataOf("file_path" to photoPath)) .build()

4Background 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.ktclass 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 MainActivityfun 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.ktclass BootReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent?) { if (intent?.action == Intent.ACTION_BOOT_COMPLETED) { scheduleSync(context) // Re-schedule periodic sync after reboot } } }

5Scheduling 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 minutesval 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 chainval 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 mergeval 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 workWorkManager.getInstance(context).enqueueUniqueWork( "upload_photo", ExistingWorkPolicy.REPLACE, // Replace if already queued uploadRequest )

Cancel and tag work

Kotlin — Tags and cancellationval 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 retryval retryWork = OneTimeWorkRequestBuilder<UploadWorker>() .setBackoffCriteria( BackoffPolicy.EXPONENTIAL, 10, TimeUnit.SECONDS ) .build()

6Hands-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?

AInstant main thread UI
BDeferrable work runs eventually with constraints
CReplaces Activity
DSQL migrations only
Explanation: Survives reboots and Doze; respects battery optimizations.
2

Worker class extends?

AFragment
BActivity
CWorker or CoroutineWorker
DService only
Explanation: CoroutineWorker uses suspend doWork() for Kotlin coroutines.
3

One-time work enqueued with?

ARoom insert
BstartActivity
CsendBroadcast only
DWorkManager.enqueue(OneTimeWorkRequest)
Explanation: OneTimeWorkRequestBuilder creates single execution work.
4

PeriodicWorkRequest minimum interval?

A15 minutes
B1 second
C1 hour only
D1 day fixed
Explanation: Platform minimum for periodic work is 15 minutes.
5

Constraints can require?

AOnly GPS always
BNetwork, charging, battery not low
COnly camera
DOnly UI visible
Explanation: Set Constraints.Builder requirements before enqueue.
6

WorkManager survives?

AOnly while Activity visible
BNothing
CApp kill and device reboot
DGradle sync only
Explanation: WorkManager persists work across process death and reboot until completed or cancelled.
7

Unique work name used for?

ACamera capture
BEncryption
CLayout inflation
DEnqueue uniquely — REPLACE or KEEP policy
Explanation: enqueueUniqueWork prevents duplicate sync jobs.
8

doWork() should return?

AResult.success(), failure(), or retry()
Bvoid only
CActivity intent
DSQL cursor
Explanation: Result determines retry behavior on failure.
9

WorkManager replaces for most apps?

AAll UI code
BAlarmManager + JobScheduler boilerplate
CRoom database
DViewBinding
Explanation: Recommended API for background deferrable tasks.
10

Input data to Worker via?

AManifest
BSharedPreferences only
CData.Builder put values in WorkRequest
DToast
Explanation: Pass primitives and strings in Data — size limited.

10 Advanced WorkManager & Background Tasks MCQs

11

CoroutineWorker vs Worker?

AIdentical
BCoroutineWorker suspend doWork on background coroutine
CWorker faster always
DCoroutineWorker main thread
Explanation: Prefer CoroutineWorker for Kotlin async code.
12

Chained work?

AManifest only
BImpossible
CbeginWith(workA).then(workB).enqueue()
DSingle Worker only
Explanation: WorkContinuation sequences dependent tasks.
13

Expedited work (12+)?

ASame as periodic
BFree unlimited
CBanned
DRuns faster with quota limits
Explanation: setExpedited for user-initiated urgent background work.
14

WorkInfo.State FAILED means?

AWork finished with failure result
BStill running
CCancelled only
DSuccess
Explanation: Observe WorkInfo live data or Flow for status.
15

Battery not low constraint?

ARequires charging only
BRequires battery above threshold
CRequires WiFi
DRequires camera
Explanation: setRequiresBatteryNotLow(true) in Constraints.
16

Hilt Worker injection?

AManual new only
BImpossible
C@HiltWorker + AssistedInject for DI in workers
DManifest meta-data only
Explanation: Hilt provides WorkerFactory for dependency injection.
17

Cancel work by?

Aadb reboot
BstopService only
Cfinish Activity
DWorkManager.cancelWorkById or cancelUniqueWork
Explanation: Cancel pending or running work when user logs out etc.
18

Retry with backoff?

AResult.retry() applies backoff policy
BImmediate infinite loop
CCrash
DANR
Explanation: setBackoffCriteria on WorkRequest for exponential backoff.
19

WorkManager vs AlarmManager exact alarms?

ASame API
BWorkManager for flexible deferrable; AlarmManager for precise time alarms
CAlarmManager always better
DWorkManager for exact clock
Explanation: Exact alarms need SCHEDULE_EXACT_ALARM permission on 12+.
20

Testing WorkManager?

AProduction only
BCannot test
CTestDriver set all constraints met; run synchronously in tests
DEmulator banned
Explanation: androidx.work:work-testing provides TestListenableWorkerBuilder.
Click an option to select, then check answers.

WorkManager & Background Tasks Interview Q&A

15 topic-focused questions for interviews and revision.

1What is WorkManager?easy
Answer: Jetpack library scheduling guaranteed background work respecting system optimizations and constraints.
2Create and enqueue one-time worker.easy
Answer: val req = OneTimeWorkRequestBuilder().build(); WorkManager.getInstance(ctx).enqueue(req)
3Periodic sync every 24 hours.medium
Answer: PeriodicWorkRequestBuilder(24, TimeUnit.HOURS).setConstraints(...).build() — note 15 min minimum for short intervals.
4Pass data to Worker.easy
Answer: OneTimeWorkRequestBuilder.from(inputData).build() where inputData built with Data.Builder.
5Return retry on network failure.medium
Answer: doWork(): return if (success) Result.success() else Result.retry()
6Constraints example for upload.easy
Answer: Requires network connected: Constraints.Builder().setRequiredNetworkType(CONNECTED).build()
7WorkManager vs Foreground Service.medium
Answer: WorkManager for deferrable background; foreground service for user-visible ongoing tasks.
8Unique work REPLACE policy.medium
Answer: enqueueUniqueWork("sync", ExistingWorkPolicy.REPLACE, request) replaces pending work with same name.
9Observe work status.medium
Answer: WorkManager.getWorkInfoByIdLiveData(id).observe { state -> ... }
10Chain download then process.medium
Answer: WorkManager.beginWith(downloadWork).then(processWork).enqueue()
11Why not Thread.sleep in Worker for hours?hard
Answer: Workers should finish quickly; schedule periodic or split work; long tasks may be stopped.
12CoroutineWorker example.medium
Answer: override suspend fun doWork(): Result = withContext(Dispatchers.IO) { api.sync(); Result.success() }
13Cancel sync on logout.easy
Answer: WorkManager.cancelUniqueWork("user_sync")
14WorkManager and Doze mode.hard
Answer: WorkManager batches work during Doze and runs when constraints met — respects battery.
15Migration from IntentService.medium
Answer: Replace with CoroutineWorker or Worker; enqueue via WorkManager instead of startService.