Using Android WorkManager to Reliably Sync Data After Device Reboot
Learn how to use Android WorkManager to guarantee background task execution after a reboot, with a concrete worker example, constraints, and observation via LiveData.
26 Jul 2026, 23:03 UTC

The problem: background work that survives reboots
Imagine an app that needs to upload a batch of sensor readings to a remote server. If the user reboots the phone or the system kills the app to free memory, a simple AsyncTask or Service started from the UI thread will be lost, and the data may never be sent. Developers need a way to guarantee that the upload runs at least once, even after a device restart, while respecting battery‑optimization rules.
Thesis: WorkManager provides a system‑level API that picks the best available background scheduler and guarantees task completion.
By defining a Worker subclass and enqueuing a OneTimeWorkRequest with appropriate constraints, the Android framework will execute the work using JobScheduler (API 23+), a fallback dispatcher, or AlarmManager as needed. The work persists across reboots and is observable via LiveData or Flow.
Implementing a Worker
First add the WorkManager dependency (version 2.7.0 is used in the examples):
dependencies {
implementation "androidx.work:work-runtime:2.7.0"
}
Create a Kotlin class that does the actual upload. The doWork() method must return a Result indicating success, failure, or a request to retry.
class SyncWorker(appContext: Context, workerParams: WorkerParameters) :
CoroutineWorker(appContext, workerParams) {
override suspend fun doWork(): Result {
// Replace with real upload logic
val success = uploadSensorData()
return if (success) Result.success() else Result.retry()
}
private fun uploadSensorData(): Boolean {
// Simulate network call; return true on success
// In a real app, handle exceptions and return false on failure
return true
}
}
The worker uses CoroutineWorker to allow suspending functions; a plain Worker would work similarly with a blocking doWork().
Scheduling the work with constraints
We want the upload to run only when the device is charging and has an unmetered network, and we want it to execute as soon as those conditions are met after a reboot.
val syncWork = OneTimeWorkRequestBuilder<SyncWorker>
.setConstraints(
Constraints.Builder()
.setRequiredNetworkType(NetworkType.UNMETERED)
.setRequiresCharging(true)
.build()
)
.build()
WorkManager.getInstance(context).enqueueUniqueWork(
"sensor_sync",
ExistingWorkPolicy.REPLACE,
syncWork
)
The call to enqueueUniqueWork ensures that only one sync request exists at a time; if a previous request is still pending, it is replaced.
Observing the outcome
WorkManager exposes a LiveData that emits the work’s state. The UI can observe it to show a toast or update a progress indicator.
WorkManager.getInstance(context)
.getWorkInfoByIdLiveData(syncWork.id)
.observe(lifecycleOwner) { workInfo ->
if (workInfo?.state == WorkInfo.State.SUCCEEDED) {
Toast.makeText(context, "Sync completed", Toast.LENGTH_SHORT).show()
} else if (workInfo?.state == WorkInfo.State.FAILED) {
Toast.makeText(context, "Sync failed", Toast.LENGTH_SHORT).show()
}
}
For quick verification during development, you can watch the logcat output from the worker:
adb logcat | grep SyncWorker
When the constraints are satisfied, you should see the log statements from doWork() appear.
Trade‑off and limitation
WorkManager does not guarantee exact execution time. On Android 12 and higher, periodic work cannot be scheduled with an interval shorter than 15 minutes due to system‑wide battery‑optimization restrictions. If your app needs near‑real‑time updates, you must combine WorkManager with a foreground service or use high‑priority Firebase Cloud Messaging to trigger the work.
Another consideration is that the worker runs in a background process that may be terminated if the system is under extreme memory pressure. In that case, WorkManager will reschedule the work, but any in‑progress state is lost, so the worker should be idempotent or checkpoint progress to persistent storage.
Actionable closing
To start using WorkManager for reliable background tasks:
- Add the
androidx.work:work-runtimedependency to your module’sbuild.gradle. - Create a
Worker(orCoroutineWorker) that performs the task and returns an appropriateResult. - Define a
OneTimeWorkRequestorPeriodicWorkRequestwith constraints such as charging, network type, or storage availability. - Enqueue the work using
enqueueUniqueWork(orenqueueUniquePeriodicWork) to avoid duplicates. - Observe
WorkInfovia LiveData or Flow to update the UI or handle errors. - Validate the behavior with
adb logcatand, for unit tests, theTestListenableWorkerBuilderAPI.
By following these steps, you gain a battery‑friendly, system‑managed mechanism that survives app kills and device reboots, ensuring your critical background work eventually runs.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.