WorkManager is an Android Jetpack library designed for executing deferred and background tasks with guaranteed execution. Unlike Service or JobScheduler, WorkManager manages the task lifecycle: it restarts on failure, adapts to the Android version, and takes device constraints into account. According to Android Developers, 2026, WorkManager is the preferred solution for most background operations in modern Android development.
Key Takeaways
WorkManager is part of Android Jetpack, a library for managing background tasks that must execute guaranteed, regardless of whether the app is in the foreground or has been closed by the user. The library supports API 14+ and automatically selects the appropriate execution mechanism: JobScheduler on Android 5+, BroadcastReceiver + AlarmManager on older versions.
The key feature of WorkManager is guaranteed execution. If a task was not completed due to device reboot, app termination, or crash, WorkManager will restart it at the next opportunity. This makes the library an ideal choice for execution-critical tasks: sending analytics, database synchronization, log uploads.
Unlike Background Service, WorkManager does not require thread and lifecycle management. The library itself creates a thread pool, handles Doze Mode, takes the Android version into account, and provides a unified API regardless of API level. Coroutine and RxJava support is available through CoroutineWorker and RxWorker respectively.
WorkManager provides built-in LiveData support for tracking task states. The getWorkInfoByIdLiveData method returns LiveData<WorkInfo> that updates on every state change: ENQUEUED, RUNNING, SUCCEEDED, FAILED, CANCELLED. This allows UI components to react to changes without manual polling of the scheduler and without memory leaks thanks to Lifecycle-aware components.
WorkManager.getInstance(context)
.getWorkInfoByIdLiveData(syncRequest.id)
.observe(viewLifecycleOwner) { workInfo ->
when (workInfo.state) {
WorkInfo.State.SUCCEEDED ->
showSuccess()
WorkInfo.State.FAILED ->
showError(workInfo.outputData)
else ->
showProgress()
}
}
Architecture of WorkManager is built around three base classes: Worker, WorkRequest, and WorkManager. Worker contains the task logic, WorkRequest describes execution parameters, and WorkManager manages the queue and scheduling. The library uses an internal Room database to store the state of all tasks.
Worker is an abstract class with a single method doWork that is called on a background thread. The method returns ListenableWorker.Result — SUCCESS, FAILURE, or RETRY. WorkRequest links the Worker with parameters: timeout, tag, initial delay, and constraints.
class SyncWorker(
context: Context,
params: WorkerParameters
) : Worker(context, params) {
override fun doWork(): Result {
return try {
val api = RetrofitClient.api
val response = api.syncData()
Result.success()
} catch (e: Exception) {
Result.retry()
}
}
}
WorkManager uniformly schedules tasks regardless of Android version. When enqueue is called, the library saves the task to Room, evaluates current conditions, and selects the optimal execution time. Under the hood, it may use JobScheduler, AlarmManager, or its own scheduler — the developer does not need to worry about it.
val syncRequest = OneTimeWorkRequestBuilder<SyncWorker>()
.setInitialDelay(15, TimeUnit.MINUTES)
.addTag("sync")
.build()
WorkManager.getInstance(context)
.enqueue(syncRequest)
WorkManager supports two types of execution requests: one-time and periodic. The choice of type depends on the scenario: the task should run once or repeat at a given interval.
OneTimeWorkRequest is designed for tasks that should execute once. This can be log submission, data synchronization after authorization, configuration download on first launch. Delay is set via setInitialDelay, and constraints via setConstraints.
PeriodicWorkRequest is suitable for repeating tasks with a minimum interval of 15 minutes. The library guarantees that the interval between runs will not be less than specified, but may be longer due to device constraints. For tasks with frequency less than 15 minutes, use Handler or Timer in Foreground Service.
| Parameter | OneTimeWorkRequest | PeriodicWorkRequest |
|---|---|---|
| Frequency | one-time | repeated (min 15 min) |
| Count | 1 execution | until cancelled |
| Delay | setInitialDelay | setInitialDelay |
| Chaining | supported | no |
| Usage | download, sync | monitoring, polling |
Constraints in WorkManager allow you to set conditions under which a task can be launched: network connectivity (NetworkType), battery level (batteryNotLow), storage state (StorageNotLow), and idle mode (DeviceIdle). The task will not start until all constraints are met.
val constraints = Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.setRequiresCharging(true)
.setRequiresBatteryNotLow(true)
.build()
val request = OneTimeWorkRequestBuilder<ImageUploadWorker>()
.setConstraints(constraints)
.build()
Chaining allows you to organize sequential or parallel task execution. beginWith starts a chain, then adds the next Worker that will execute after the successful completion of the previous one. For parallel execution, use workManager.enqueue(listOf(request1, request2)).
WorkManager.getInstance(context)
.beginWith(compressWorker)
.then(uploadWorker)
.then(cleanupWorker)
.enqueue()
// compress -> upload -> cleanup sequentially
JobScheduler was introduced in Android 5 (API 21) as a system service for scheduling background tasks. WorkManager came to replace it, offering a cross-platform API with automatic migration and additional capabilities: chaining, execution guarantee, tags, state observation via LiveData.
When migrating from JobScheduler to WorkManager, you need to convert JobService to Worker, replace JobInfo with WorkRequest, and Context.getSystemService with WorkManager API. WorkManager automatically handles compatibility issues and handles Doze Mode more correctly than a manual JobScheduler implementation. Migration steps: 1) create a Worker class, 2) build a WorkRequest with the same conditions, 3) remove JobService and JobInfo from code and manifest.
WorkManager supports the concept of unique tasks through ExistingWorkPolicy. If a task with the specified name already exists, the policy determines the behavior: KEEP (do not create a new one), REPLACE (replace the existing one), APPEND (append to the end of the chain), and APPEND_OR_REPLACE. UniqueWorkRequest is convenient for tasks that should not be duplicated: database synchronization, configuration download, analytics batch submission.
WorkManager.getInstance(context)
.enqueueUniqueWork(
"sync_data",
ExistingWorkPolicy.KEEP,
syncRequest
)
CoroutineWorker supports the setProgress mechanism, allowing you to pass intermediate execution results. This is useful for long-running operations: large file download, batch image processing, database migration. The UI can subscribe to updates via getWorkInfosByTagLiveData and display real-time progress. The ForegroundInfo method is also available to run a Worker as a Foreground Service with a notification if the task should be visible to the user.
class ProgressWorker(
context: Context,
params: WorkerParameters
) : CoroutineWorker(context, params) {
override suspend fun doWork(): Result {
val total = 100
for (i in 1..total) {
setProgress(
workDataOf("progress" to i)
)
}
return Result.success()
}
}
WorkManager supports data transfer between Workers via InputData and OutputData. InputData is created during WorkRequest construction via Data.Builder and is passed to the Worker through inputData. After execution, the Worker creates OutputData via workDataOf or Data.Builder and returns it together with Result.success(outputData). The next Worker in the chain receives the outputData of the previous one as its inputData. Data is stored in key-value format with support for basic types: String, Int, Long, Boolean, Double. The maximum Data size is 10 KB.
In practice, many projects use WorkManager as the sole background task scheduler. Google recommends migrating all existing JobService to WorkManager, especially in apps supporting Android 4.4 (API 19) and below, where JobScheduler is unavailable and WorkManager uses a fallback mechanism via AlarmManager and BroadcastReceiver. For testing, WorkManager provides TestListenableWorkerBuilder and TestWorkerBuilder, which allow testing Workers in JUnit tests without a real scheduler.
For testing WorkManager, use TestListenableWorkerBuilder from AndroidX Test, which allows running Workers in an isolated environment and checking the returned Result. The library provides full JUnit and Robolectric support for unit testing without a real scheduler. Overall, WorkManager is suitable for 80% of tasks where Service or JobScheduler were previously used.
Frequently Asked Questions
Yes, WorkManager guarantees execution even after reboot. The library saves all incomplete tasks in a Room database and restores them using BroadcastReceiver that triggers after system boot.
Worker runs on a background thread without coroutine or RxJava support. CoroutineWorker uses Kotlin coroutines with support for suspend functions and cancellation via coroutine scope. RxWorker works with Observable and Single, suitable for reactive chains.
Use workManager.cancelWorkById(id) or workManager.cancelAllWorkByTag("tag"). The library also provides the cancelUniqueWork("name") method for canceling unique tasks with the specified name.
The minimum interval for PeriodicWorkRequest is 15 minutes. This limitation is set by Google to prevent excessive battery drain. If a task needs to run more frequently, use Foreground Service or Handler with a timer.
Yes, WorkManager supports API 14+. On devices without JobScheduler (below API 21), the library uses a combination of AlarmManager and BroadcastReceiver for task scheduling. This makes WorkManager a universal solution for background tasks.
Summary
We will develop a mobile application turnkey
IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.
Read also