WorkManager vs AlarmManager: Android Background Execution Guide
Choose WorkManager for deferrable Android background work under Doze and App Standby; reserve exact alarms for user-facing timing.
23 Oct 2025, 06:19 UTC

The decision: deferrable work that survives app exit
You need code to run after the user leaves your screen, and it should still run if the system kills the process or the device reboots. The work does not have to happen at an exact clock time; it just needs to complete eventually, preferably when the device is on a network, charging, or not in a low-power state. Under those constraints, the choice is usually between WorkManager and AlarmManager.
Useful takeaway: choose WorkManager for deferrable, constraint-driven background work. Use AlarmManager only for user-facing, time-sensitive alarms, and only after requesting the SCHEDULE_EXACT_ALARM special app access on Android 12 and later.
Constraints that shape the choice
- Doze restricts background CPU and network access when the device is stationary and the screen is off.
- App Standby limits apps the user has not launched recently.
- Android 12 and later require SCHEDULE_EXACT_ALARM for exact alarms, and users can revoke it in Settings.
- WorkManager does not guarantee exact execution time; it is for deferrable work only.
Supported options compared
| Option | Best for | Battery restrictions | Exact timing | Survives reboot |
|---|---|---|---|---|
| WorkManager | Deferrable background work with constraints such as network, charging, and storage | Respects Doze and App Standby; runs during system maintenance windows | No | Yes |
| AlarmManager setExactAndAllowWhileIdle | User-facing alarms that must fire at a specific time | Exempt from some Doze restrictions; requires SCHEDULE_EXACT_ALARM on Android 12+ | Yes | Yes |
| AlarmManager inexact alarms | Non-critical timing with flexible delivery windows | Deferred during Doze until the next maintenance window | No | Yes |
| Foreground Service | Immediate, user-visible work such as media playback or navigation | Visible notification required; higher battery cost; type declarations required on Android 14+ | Yes | No, unless restarted |
Trade-offs
WorkManager selects the execution backend automatically, using JobScheduler on Android 5.0 and later and older fallback paths on very old devices. It handles retry, backoff, and chaining out of the box, but the system decides when constraints are satisfied. That makes it unsuitable for a medication reminder at exactly 8:00 AM.
AlarmManager fires at the requested time even in Doze when using setExactAndAllowWhileIdle, but on Android 12 and later your app must hold SCHEDULE_EXACT_ALARM. The user can revoke that access at any time from Settings > Apps > Special app access > Alarms and reminders, after which exact alarms stop working without warning.
Implementation: enqueue constrained work with WorkManager
Add the WorkManager library to your app module's build.gradle file, then sync the project in Android Studio:
dependencies {
def workVersion = "2.9.0"
implementation "androidx.work:work-runtime:$workVersion"
}
Version assumption: WorkManager 2.9.0 or later. Check the AndroidX release notes for the latest stable version before a production build.
Create a Worker class and a one-time request with constraints:
import android.content.Context;
import androidx.work.Constraints;
import androidx.work.NetworkType;
import androidx.work.OneTimeWorkRequest;
import androidx.work.WorkManager;
import androidx.work.Worker;
import androidx.work.WorkerParameters;
import androidx.work.ExistingWorkPolicy;
public class SyncWorker extends Worker {
public SyncWorker(Context context, WorkerParameters params) {
super(context, params);
}
@Override
public Result doWork() {
// Perform deferrable background work here.
return Result.success();
}
}
Constraints constraints = new Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.setRequiresCharging(false)
.setRequiresBatteryNotLow(true)
.build();
OneTimeWorkRequest syncRequest = new OneTimeWorkRequest.Builder(SyncWorker.class)
.setConstraints(constraints)
.build();
WorkManager.getInstance(context)
.enqueueUniqueWork("daily-sync", ExistingWorkPolicy.KEEP, syncRequest);
Where to run: in your app's Kotlin or Java source, typically from an Activity, Fragment, or Application subclass. Required permissions: none beyond normal installation. Expected check: the worker runs when the device has a network connection and battery is not low. Risk: if the device remains in Doze or App Standby, execution may be delayed until the next maintenance window.
Validate execution and diagnose the backend
- Open Logcat in Android Studio and filter by the
WorkManagertag and your worker class name. - Force the device into Doze from a host computer terminal with USB debugging enabled:
adb shell dumpsys deviceidle force-idle
Where to run: host terminal connected to an emulator or physical device through adb. Permissions: Developer Options and USB debugging must be enabled on the device. Expected check: Logcat shows WorkManager deferring execution until the system leaves idle or enters a maintenance window. Risk: force-idle defers all device maintenance, so use a disposable emulator or test device.
To confirm exact-alarm eligibility on Android 12+, open Settings > Apps > Special app access > Alarms and reminders and verify your app is allowed. If it is not listed, exact alarms will not fire even if the code calls setExactAndAllowWhileIdle.
Limitations and how to check the result
- WorkManager cannot guarantee a specific clock time. Use AlarmManager with SCHEDULE_EXACT_ALARM for exact timing instead.
- WorkManager work can start shortly after constraints become true, not instantly.
- Check the result by observing
WorkManager.getInstance(context).getWorkInfoByIdLiveData(request.id)and confirming the state moves fromENQUEUEDtoRUNNING, thenSUCCEEDEDorFAILED.
Rollback
Enqueuing work changes system scheduling state. Cancel pending work with:
WorkManager.getInstance(context).cancelUniqueWork("daily-sync");
Cancellation affects only pending or queued requests. Work already running cannot be rolled back.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.