AlarmManager — یک سرویس سیستمی Android است که به برنامهها اجازه میدهد وظایف را در زمان مشخصی اجرا کنند، حتی اگر برنامه اجرا نشده باشد یا دستگاه در حالت خواب باشد. برخلاف JobScheduler یا WorkManager، AlarmManager دقت اجرا را تضمین میکند که آن را برای هشدارها، یادآوریهای تقویمی و وظایف حساس به زمان ضروری میسازد. طبق Android Developers, 2026، از Android 4.4 به بعد setRepeating بهعنوان تکرار نادقیق عمل میکند و برای هشدارهای دقیق به setExact یا setAlarmClock نیاز است.
نکات اصلی
AlarmManager — یک سرویس سیستمی Android است که API برای برنامهریزی وظایف با زمان اجرای دقیق یا تقریبی ارائه میدهد. از اولین نسخه Android وجود داشته و همچنان تنها راه قابل اعتماد برای اجرای کد در یک لحظه مشخص، صرفنظر از وضعیت برنامه و دستگاه است.
اصل کار ساده است: برنامه یک PendingIntent با زمان اجرا به سیستم ارسال میکند. وقتی لحظه مورد نظر فرا میرسد، سیستم Intent را به BroadcastReceiver ثبتشده ارسال میکند یا Service را راهاندازی میکند. حتی اگر دستگاه در حالت خواب بوده باشد، WakeLock به پردازنده اجازه بیدار شدن و پردازش رویداد را میدهد.
حوزه اصلی کاربرد AlarmManager — وظایفی که نیاز به زمان دقیق دارند: هشدارها، یادآوریهای تقویمی، راهاندازی عملیات طولانی در ساعت مشخص. برای وظایفی که دقت در آنها حیاتی نیست (همگامسازی روزانه)، Google WorkManager یا JobScheduler را توصیه میکند زیرا آنها بهینهتر از نظر مصرف انرژی هستند.
AlarmManager از برنامه PendingIntent و زمان اجرا را دریافت میکند. سیستم این درخواست را در برنامهریز داخلی خود ذخیره میکند و پردازنده را در زمان مشخص شده برای تحویل Intent بیدار میکند. توسعهدهنده باید از قبل BroadcastReceiver را ثبت کند که این Intent را پردازش کند.
AlarmManager از 4 نوع هشدار پشتیبانی میکند: ELAPSED_REALTIME (زمان از راهاندازی، بیدار نمیکند)، RTC (زمان واقعی، بیدار نمیکند)، ELAPSED_REALTIME_WAKEUP (زمان از راهاندازی، دستگاه را بیدار میکند) و RTC_WAKEUP (زمان واقعی، بیدار میکند). نسخههای WAKEUP زمانی ضروری هستند که وظیفه باید حتی در حالت خواب دستگاه اجرا شود.
| نوع | زمان | بیدار میکند | مثال |
|---|---|---|---|
| ELAPSED_REALTIME | از راهاندازی | خیر | تایمر مدت کار |
| RTC | Unix timestamp | خیر | ثبت رویداد |
| ELAPSED_REALTIME_WAKEUP | از راهاندازی | بله | وظیفه دورهای |
| RTC_WAKEUP | Unix timestamp | بله | هشدار |
از Android 12 (API 31) به بعد، برای استفاده از هشدارهای دقیق (setExact) مجوز SCHEDULE_EXACT_ALARM الزامی است. کاربر میتواند آن را از طریق تنظیمات لغو کند. برای برنامههایی که نیاز به هشدار دقیق با نمایش دارند (مثلاً ساعت)، از USE_EXACT_ALARM استفاده میشود که در زمان نصب اعطا میگردد.
AlarmManager سه روش اصلی برای برنامهریزی وظایف ارائه میدهد. انتخاب روش دقت اجرا و تأثیر بر مصرف انرژی دستگاه را تعیین میکند.
set — روش پایه برای اجرای یکباره نادقیق. سیستم میتواند زمان را تا چند دقیقه برای گروهبندی با رویدادهای دیگر جابجا کند. برای وظایفی که دقت در آنها حیاتی نیست مناسب است: یادآوری برای ورود به برنامه.
setRepeating — روش برای تکرار دورهای. از Android 4.4 (API 19) به بعد setRepeating نادقیق شد — فواصل زمانی ممکن است تغییر کنند. سیستم دیگر دوره ثابت را تضمین نمیکند. به جای setRepeating توصیه میشود از setExact با برنامهریزی مجدد دستی یا WorkManager با PeriodicWorkRequest استفاده کنید.
setExact — روش برای اجرای دقیق یکباره. سیستم دستگاه را در نزدیکترین زمان ممکن به زمان مشخص شده بیدار میکند. setAlarmClock — حالت ویژه setExact است که همچنین آیکون هشدار را در نوار وضعیت نشان میدهد و بالاترین اولویت را در میان همه انواع هشدارها دارد.
val alarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
// هشدار دقیق یکباره
val intent = Intent(this, AlarmReceiver::class.java)
val pendingIntent = PendingIntent.getBroadcast(
this, 0, intent,
PendingIntent.FLAG_IMMUTABLE
)
alarmManager.setAlarmClock(
AlarmManager.AlarmClockInfo(
targetTime, pendingIntent
),
pendingIntent
)
سناریوی معمول — ایجاد یک یادآوری روزانه در زمان مشخص. برای این کار از RTC_WAKEUP با setExact استفاده میشود. هنگام اجرا، BroadcastReceiver یک اعلان یا Service را راهاندازی میکند. پس از پردازش، باید وظیفه را برای روز بعد دوباره برنامهریزی کرد.
class ReminderReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent?) {
val notificationManager =
context.getSystemService(Context.NOTIFICATION_SERVICE)
as NotificationManager
val notification = NotificationCompat.Builder(
context, "reminder_channel"
)
.setContentTitle("یادآوری")
.setContentText("زمان انجام وظیفه فرا رسیده است")
.setSmallIcon(R.drawable.ic_reminder)
.build()
notificationManager.notify(1001, notification)
}
}
برای تکرار روزانه از setExact با محاسبه اجرای بعدی استفاده میشود. در Intent میتوان flagهایی برای شناسایی انواع مختلف یادآوریها ارسال کرد. اطمینان حاصل کنید که BroadcastReceiver در AndroidManifest.xml با پردازش action WAKEUP ثبت شده است.
fun scheduleDailyReminder(context: Context, hour: Int, minute: Int) {
val calendar = Calendar.getInstance().apply {
set(Calendar.HOUR_OF_DAY, hour)
set(Calendar.MINUTE, minute)
set(Calendar.SECOND, 0)
if (before(Calendar.getInstance())) {
add(Calendar.DAY_OF_MONTH, 1)
}
}
val alarmManager =
context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
alarmManager.setExactAndAllowWhileIdle(
AlarmManager.RTC_WAKEUP,
calendar.timeInMillis,
pendingIntent
)
}
AlarmManager — ابزاری قدرتمند اما پرمصرف از نظر انرژی است. هر هشدار WAKEUP دستگاه را از حالت خواب خارج میکند که باتری مصرف میکند. Google توصیه میکند استفاده از هشدارهای دقیق را به حداقل برسانید و در Android 6+ از setExactAndAllowWhileIdle برای کاهش تأثیر بر Doze Mode استفاده کنید. برای وظایف دورهای بدون نیاز به دقت، از WorkManager با PeriodicWorkRequest استفاده کنید که نیازی به بیدار کردن دستگاه ندارد و در هر بار اجرا باتری مصرف نمیکند.
برای تست AlarmManager از TestAlarmManager موجود در Android Test Framework استفاده کنید. این امکان شبیهسازی اجرای هشدار بدون انتظار برای زمان واقعی را فراهم میکند. در Robolectric، ShadowAlarmManager در دسترس است که فراخوانیهای set، setExact و setRepeating را رهگیری کرده و روشهایی برای اجرای اجباری و بررسی تعداد وظایف برنامهریزیشده ارائه میدهد. برای تستهای واحد BroadcastReceiver از Robolectric.getForegroundScheduler() استفاده کنید. همچنین تست Espresso با IdlingResource در دسترس است که در تستهای یکپارچهسازی منتظر اجرای هشدار میماند.
اگر برنامه از AlarmManager برای وظایف دورهای بدون نیاز به زمان دقیق استفاده میکند، مهاجرت به WorkManager را در نظر بگیرید. PeriodicWorkRequest با حداقل فاصله ۱۵ دقیقه جایگزین setRepeating میشود، در حالی که WorkManager اجرا پس از راهاندازی مجدد را تضمین میکند، Doze Mode را مدیریت میکند و نیازی به مجوز SCHEDULE_EXACT_ALARM ندارد. برای وظایف حساس به زمان (هشدار ساعت ۷ صبح)، AlarmManager تنها انتخاب صحیح باقی میماند. استراتژی بهینه — استفاده از AlarmManager فقط برای هشدارها با setAlarmClock، و انتقال تمام وظایف پسزمینه دیگر به WorkManager.
برای وظایف دورهای بدون نیاز به دقت از WorkManager با PeriodicWorkRequest استفاده کنید. برای وظایف با زمان دقیق اما غیرحساس به اجرا در حالت خواب — setExact بدون WAKEUP. و فقط برای هشدارها با بیدار کردن اجباری — setAlarmClock یا RTC_WAKEUP.
همچنین بررسی وجود مجوز SCHEDULE_EXACT_ALARM در Android 12+ مهم است. اگر مجوز داده نشده باشد، setExact مانند set معمولی (نادقیق) کار میکند. برای بررسی از AlarmManager.canScheduleExactAlarms() استفاده کنید. در صورت عدم وجود مجوز، میتوانید به کاربر پیشنهاد دهید از طریق Intent(Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM) به تنظیمات برود.
ویژگی حیاتی AlarmManager — تمام هشدارهای برنامهریزیشده پس از راهاندازی مجدد دستگاه بازنشانی میشوند. برای بازیابی آنها باید BroadcastReceiverای اعلام کنید که Intent.ACTION_BOOT_COMPLETED را پردازش کرده و تمام هشدارهای فعال را در متد onReceive دوباره برنامهریزی کند. بدون این، کاربر پس از خاموش و روشن کردن تلفن، تمام یادآوریهای خود را از دست خواهد داد.
class BootReceiver : BroadcastReceiver() {
override fun onReceive(
context: Context,
intent: Intent
) {
if (intent.action ==
Intent.ACTION_BOOT_COMPLETED
) {
val prefs =
context.getSharedPreferences("alarms", 0)
val savedTime =
prefs.getLong("next_alarm", 0L)
if (savedTime > System.currentTimeMillis()) {
scheduleReminder(context, savedTime)
}
}
}
}
در عمل AlarmManager بهترین راهحل برای برنامههای هشدار، تقویمها، یادآوریهای مصرف دارو و هر وظیفهای که زمان اجرا برای کاربر حیاتی است باقی میماند. برای تمام سناریوهای دیگر کار پسزمینه، WorkManager یا JobScheduler ترجیح داده میشوند.
هنگام انتخاب بین AlarmManager و WorkManager از این قانون پیروی کنید: اگر کاربر صریحاً درخواست یادآوری در ساعت ۱۴:۳۰ کرده است — از AlarmManager با setAlarmClock استفاده کنید. اگر وظیفه باید «تقریباً هر ساعت یک بار» اجرا شود — WorkManager با PeriodicWorkRequest بهینهتر و قابل اعتمادتر خواهد بود.
سوالات متداول
هر دو روش اجرای دقیق را تضمین میکنند، اما setAlarmClock علاوه بر این آیکون هشدار را در نوار وضعیت نشان میدهد و به سیستم اطلاع میدهد که این یک هشدار برای کاربر است. در Android 6+ setAlarmClock از Doze Mode مصون است، در حالی که setExact ممکن است به تأخیر بیفتد.
پس از راهاندازی مجدد، تمام هشدارهای برنامهریزیشده بازنشانی میشوند. برای بازیابی باید یک BroadcastReceiver برای action BOOT_COMPLETED ثبت کنید و تمام وظایف را در onReceive دوباره برنامهریزی کنید. بدون این، هیچ هشداری پس از روشن شدن دستگاه کار نخواهد کرد.
از API 19 به بعد setRepeating نادقیق شد — سیستم ممکن است فواصل را برای صرفهجویی در انرژی تغییر دهد. به جای آن از setExact با برنامهریزی مجدد دستی یا WorkManager با PeriodicWorkRequest استفاده کنید که رفتار قابل پیشبینیتری ارائه میدهد.
برای setExact مجوز SCHEDULE_EXACT_ALARM لازم است که کاربر میتواند در تنظیمات اعطا یا لغو کند. برای setAlarmClock با نمایش در رابط ساعت از USE_EXACT_ALARM استفاده میشود که به طور خودکار هنگام نصب از فروشگاه اعطا میگردد.
خیر، AlarmManager همیشه از طریق PendingIntent کار میکند. این میتواند PendingIntent.getBroadcast برای BroadcastReceiver، PendingIntent.getService برای Service یا PendingIntent.getActivity برای Activity باشد. بدون PendingIntent سیستم نمیتواند رویداد را به برنامه تحویل دهد.
خلاصه
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.
همچنین بخوانید