AlarmManager & JobScheduler

Sometimes background work isn't triggered by an event – it needs to happen at a specific time, or only when certain conditions are met (charging, on WiFi). Android has offered two lower-level APIs for this for years: AlarmManager for time-based triggers, and JobScheduler for constraint-based work. This page covers both honestly, including where they now take a back seat to WorkManager.

AlarmManager: Exact Time Triggers

AlarmManager schedules something to happen at a precise future time, even if RecipeBox isn't running at that moment. It's the right tool when the trigger genuinely is a clock time – for example, a daily reminder telling the user "time to plan dinner":

// Scheduling a daily reminder at 5:00 PM
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);

Intent intent = new Intent(context, DinnerReminderReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(
        context, 0, intent, PendingIntent.FLAG_IMMUTABLE);

Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, 17);
calendar.set(Calendar.MINUTE, 0);
if (calendar.getTimeInMillis() <= System.currentTimeMillis()) {
    calendar.add(Calendar.DAY_OF_YEAR, 1); // already passed today, schedule for tomorrow
}

alarmManager.setExactAndAllowWhileIdle(
        AlarmManager.RTC_WAKEUP,
        calendar.getTimeInMillis(),
        pendingIntent);
Explanation:
  • setExactAndAllowWhileIdle() fires at (close to) the exact time requested, even in Doze mode.
  • RTC_WAKEUP uses wall-clock time and wakes the device if it's asleep.
  • A BroadcastReceiver (see Broadcast Receivers) usually receives the alarm and shows the reminder notification.

The Exact-Alarm Permission

On recent Android versions, scheduling exact alarms requires the SCHEDULE_EXACT_ALARM permission, declared in the manifest:

<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
Why the restriction? Exact alarms wake the device out of low-power states, which is expensive for battery if apps schedule them carelessly. Android now gates this capability behind an explicit permission (and, on some versions, a special user-facing settings toggle) so exact, wake-the-device timing is reserved for cases – like alarm clocks and calendar reminders – that truly need it, rather than every app defaulting to it.

JobScheduler: Constraint-Based Work

JobScheduler takes a different approach: instead of "run at this exact time", you describe conditions under which the work is allowed to run, and the system picks the best moment – batching jobs from different apps together to save battery.

// RecipeSyncJobService.java
public class RecipeSyncJobService extends JobService {
    @Override
    public boolean onStartJob(JobParameters params) {
        new Thread(() -> {
            RecipeRepository.getInstance(this).syncPendingRecipes();
            jobFinished(params, false); // false = no need to reschedule
        }).start();
        return true; // work continues on another thread
    }

    @Override
    public boolean onStopJob(JobParameters params) {
        return true; // reschedule if the system stopped it early
    }
}
// Scheduling the job: only when charging and on an unmetered network
JobScheduler scheduler = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);

JobInfo jobInfo = new JobInfo.Builder(1001,
        new ComponentName(context, RecipeSyncJobService.class))
        .setRequiresCharging(true)
        .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)
        .build();

scheduler.schedule(jobInfo);

Honest Take: JobScheduler Has Been Superseded

JobScheduler was Android's answer to constraint-based background work for years, but it's honestly been largely superseded by WorkManager. WorkManager doesn't replace JobScheduler from scratch – on the versions of Android where JobScheduler is the best available mechanism, WorkManager actually uses JobScheduler internally, alongside AlarmManager and a custom fallback executor on older API levels, and picks whichever is appropriate behind the scenes.

The practical benefit: you write against one consistent API (WorkManager) instead of branching your own code by API level to decide between JobScheduler, AlarmManager, or something else.

Reference: Comparing the Options

APIBest forGuarantees survival of app restart/reboot?Recommended today?
AlarmManager An exact, time-precise trigger (a specific clock time) Yes, if rescheduled after reboot Only when you truly need exact timing
JobScheduler Constraint-based work (charging, network) on API 21+ Yes Rarely used directly anymore – prefer WorkManager
WorkManager Deferrable, guaranteed background work with constraints Yes, across all supported API levels Yes – the default choice for new code

Recommendation

Use WorkManager for constraint-based, deferrable background work in new code – it is covered next and gives you one API that adapts to the device automatically.

Reach for AlarmManager directly only when you need an exact, time-precise trigger that WorkManager's more flexible, battery-friendly scheduling windows can't guarantee.

You generally do not need to call JobScheduler yourself anymore – let WorkManager decide when to use it under the hood.

Troubleshooting

Exact alarm never fires? → Confirm SCHEDULE_EXACT_ALARM is declared, and that the user hasn't revoked exact-alarm access in system settings.

JobScheduler job never runs? → Its constraints (charging, network type) may simply never be met at once during testing – try relaxing them temporarily to confirm the job itself works.

Alarm doesn't survive a reboot? → Re-register it from a BOOT_COMPLETED receiver; alarms don't persist across a device restart on their own.

Continue to WorkManager (Java) to see the modern, unified API that wraps these lower-level mechanisms for you.