Why BroadcastReceiver Fails and How WorkManager Saves Your Nightly Sync

This article examines the limitations of using BroadcastReceiver with AlarmManager for nightly data synchronization on Android, demonstrates how migrating to WorkManager improves reliability and battery efficiency, and provides code comparisons and guidance on choosing the right background execution tool for various scenarios.

AndroidPub
AndroidPub
AndroidPub
Why BroadcastReceiver Fails and How WorkManager Saves Your Nightly Sync

Preface

In the past, BroadcastReceiver was the go‑to solution for alarms, boot events, network changes, and in‑app communication, but by 2025 it has become unreliable for regular work.

Pain point: Unreachable broadcasts

We needed to sync user data every night at 2 AM even when the device was in standby. Using AlarmManager together with BroadcastReceiver we built such a system, but about 10 % of users failed to work because of power‑saving modes.

We later migrated the background task to WorkManager. The nightly sync became far more reliable, power‑efficient, and survived Doze mode and process kills.

Old solution: BroadcastReceiver + AlarmManager

// 1. Define a BroadcastReceiver
class SyncReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        // execute sync code...
        // problem: execution time is short and can be interrupted
    }
}

// 2. Set a repeating alarm
val alarmIntent = PendingIntent.getBroadcast(
    context, 0, Intent(context, SyncReceiver::class.java),
    PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
// setRepeating tries to wake the device
alarmManager.setRepeating(
    AlarmManager.RTC_WAKEUP,
    triggerAtMillis,
    intervalMillis,
    alarmIntent
)

This approach fails under low‑power modes, is ignored by battery‑optimization policies, and setRepeating is being deprecated because of its inaccuracy.

New solution: WorkManager

// 1. Define a Worker
class SyncWorker(appContext: Context, workerParams: WorkerParameters) :
    CoroutineWorker(appContext, workerParams) {
    // use coroutines, perfect!
    override suspend fun doWork(): Result {
        // execute sync code (continues after app restart)
        // ... sync logic ...
        return Result.success() // tell the system the task succeeded
    }
}

// 2. Schedule a unique nightly sync
val workRequest = PeriodicWorkRequestBuilder<SyncWorker>(1, TimeUnit.DAYS)
    .setInitialDelay(calculateDelayFor2AM(), TimeUnit.MILLISECONDS)
    .setConstraints(Constraints.Builder()
        .setRequiredNetworkType(NetworkType.CONNECTED)
        .build())
    .build()

WorkManager.getInstance(context).enqueueUniquePeriodicWork(
    "NightlySync",
    ExistingPeriodicWorkPolicy.REPLACE,
    workRequest
)

The task survives device reboots, respects Doze mode, and runs close to the expected time, making it very battery‑friendly.

Why we should abandon BroadcastReceiver?

Issues with BroadcastReceiver:

Background limits: Most implicit broadcasts are blocked unless the app is foreground or whitelisted.

Battery police: Android’s battery optimizations may delay or ignore the Intent.

Security risks: Exported receivers can leak data or be spoofed by malicious apps.

Maintenance pain: New Android versions add rules (e.g., PendingIntent mutability) that can break existing code.

Modern Android solutions:

WorkManager: Handles delayed and periodic background work; robust and Doze‑compatible. Preferred for most background tasks.

Foreground Service: For user‑visible long‑running tasks (music, navigation, downloads) with a persistent notification.

AlarmManager: Only for precise‑time tasks (calendar reminders, alarms) and requires SCHEDULE_EXACT_ALARM permission.

In‑app event bus: SharedFlow (Kotlin Coroutines) or EventBus for internal component communication.

FCM (Firebase Cloud Messaging): Reliable way to wake the app from remote pushes.

Choosing the right tool for the right scenario

Need to sync data? → Use WorkManager.

Need a user‑visible long‑running task? → Use ForegroundService.

Only internal app communication? → Use SharedFlow or other event bus.

Need to receive push notifications or remote commands? → Use FCM.

Need a second‑precision alarm? → Use AlarmManager cautiously with proper permissions.

Only truly need BroadcastReceiver (e.g., BOOT_COMPLETED) → Lock it with permissions and use only where documented.

Conclusion

The Android background ecosystem evolves rapidly. If BroadcastReceiver is becoming “exhausted” in your app, it’s time to let it rest and adopt more reliable mechanisms such as WorkManager.

mobile developmentAndroidBroadcastReceiverBackground TasksWorkManager
AndroidPub
Written by

AndroidPub

Senior Android Developer & Interviewer, regularly sharing original tech articles, learning resources, and practical interview guides. Welcome to follow and contribute!

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.