زمان‌بندی زنگ ساعت

زنگ‌های ساعت (براساس کلاس AlarmManager) روشی برای انجام عملیات مبتنی بر زمان خارج از طول عمر برنامه دراختیارتان قرار می‌دهد. برای مثال، می‌توانید از زنگ ساعت برای شروع عملیاتی طولانی‌مدت استفاده کنید، مثل راه‌اندازی سرویسی یک‌بار در روز برای بارگیری پیش‌بینی آب‌وهوا.

هشدارها این ویژگی‌ها را دارند:

  • این محرک‌ها به شما امکان می‌دهند «هدف‌ها» را در زمان‌ها و/یا فواصل زمانی مشخص اجرا کنید.

  • می‌توانید از آن‌ها در ترکیب با گیرنده‌های رویداد ثبت‌شده برای زمان‌بندی کارها یا WorkRequests برای انجام عملیات‌های دیگر استفاده کنید.

  • این هشدارها خارج از برنامه شما عمل می‌کنند، بنابراین می‌توانید از آن‌ها برای راه‌اندازی رویدادها یا کنش‌ها استفاده کنید، حتی زمانی که برنامه شما درحال اجرا نیست و حتی اگر خود دستگاه در حالت خواب باشد.

  • آن‌ها به شما کمک می‌کنند تا نیازهای منابع برنامه‌تان را به حداقل برسانید. می‌توانید عملیات را بدون تکیه بر زمان‌سنج‌ها یا سرویس‌های درحال اجرای مداوم زمان‌بندی کنید.

تنظیم زنگ ساعت غیردقیق

وقتی برنامه‌ای زنگ هشدار غیردقیق تنظیم می‌کند، سیستم زنگ هشدار را در زمانی در آینده ارائه می‌دهد. زنگ‌های هشدار غیردقیق تضمین‌هایی را درباره زمان‌بندی ارائه زنگ هشدار ارائه می‌دهند و درعین‌حال محدودیت‌های صرفه‌جویی در مصرف باتری مانند Doze را رعایت می‌کنند.

توسعه‌دهندگان می‌توانند از تضمین‌های API زیر برای سفارشی‌سازی زمان‌بندی ارسال زنگ هشدار غیردقیق استفاده کنند.

به‌صدا درآمدن زنگ ساعت پس‌از زمانی مشخص

اگر برنامه‌تان set()، setInexactRepeating()، یا setAndAllowWhileIdle() را فراخوانی کند، زنگ ساعت هرگز قبل‌از زمان راه‌انداز ارائه‌شده به‌صدا درنمی‌آید.

در Android 12 (سطح API‏ ۳۱) و بالاتر، سیستم زنگ ساعت را ظرف یک ساعت از زمان راه‌انداز ارائه‌شده فراخوانی می‌کند، مگراینکه محدودیت‌های صرفه‌جویی در باتری مانند بهینه‌سازی باتری یا Doze اعمال شده باشد.

ارائه هشدار درطول پنجره زمانی

اگر برنامه‌تان setWindow() را فراخوانی کند، زنگ هشدار هرگز قبل‌از زمان راه‌انداز ارائه‌شده به‌صدا درنمی‌آید. اگر هیچ‌گونه محدودیت صرفه‌جویی در مصرف باتری اعمال نشده باشد، زنگ هشدار در پنجره زمانی مشخص‌شده، با شروع از زمان راه‌انداز ارائه‌شده، ارائه می‌شود.

اگر برنامه شما Android 12 یا بالاتر را هدف قرار دهد، سیستم می‌تواند فراخوانی زنگ هشدار غیردقیق با پنجره زمانی را حداقل ۱۰ دقیقه به‌تأخیر بیندازد. به همین دلیل، مقادیر پارامتر windowLengthMillis زیر 600000 معمولاً به 600000 محدود می‌شوند. سیستم ممکن است پنجره‌های کوچک‌تری را درنظر بگیرد، به‌ویژه اگر زنگ ساعت برای به‌صدا درآمدن در آینده نزدیک زمان‌بندی شده باشد.

ارسال زنگ ساعت تکرارشونده در فواصل زمانی تقریباً منظم

اگر برنامه‌تان setInexactRepeating() را فراخوانی کند، سیستم چندین زنگ ساعت را فراخوانی می‌کند:

  1. اولین زنگ در پنجره زمانی مشخص‌شده، با شروع از زمان راه‌انداز ارائه‌شده، به‌صدا درمی‌آید.
  2. زنگ‌های بعدی معمولاً پس‌از سپری شدن پنجره زمانی مشخص‌شده به‌صدا درمی‌آیند. زمان بین دو فراخوانی متوالی زنگ هشدار می‌تواند متفاوت باشد.

تنظیم زنگ ساعت دقیق

سیستم زنگ ساعت دقیق را در لحظه دقیقی در آینده فراخوانی می‌کند.

اکثر برنامه‌ها می‌توانند بااستفاده از زنگ‌های غیردقیق، تکالیف و رویدادها را زمان‌بندی کنند تا چند مورد استفاده رایج را تکمیل کنند. اگر عملکرد اصلی برنامه‌تان به زنگ دقیقاً زمان‌بندی‌شده بستگی دارد (مثلاً برای برنامه ساعت زنگ‌دار یا برنامه تقویم)، دراین‌صورت استفاده از زنگ دقیق به‌جای آن مشکلی ندارد.

موارد استفاده‌ای که ممکن است به هشدارهای دقیق نیاز نداشته باشد

فهرست زیر گردش کارهای رایجی را نشان می‌دهد که ممکن است به زنگ ساعت دقیق نیاز نداشته باشند:

زمان‌بندی عملیات زمان‌بندی درطول عمر برنامه‌تان
کلاس Handler شامل چندین روش خوب برای مدیریت عملیات زمان‌بندی است، مانند انجام برخی کارها هر n ثانیه، درحالی‌که برنامه شما فعال است: postAtTime() و postDelayed(). توجه داشته باشید که این میاناهای برنامه‌سازی کاربردی به زمان فعال بودن دستگاه و نه زمان واقعی متکی هستند.
کار پس‌زمینه زمان‌بندی‌شده، مثل به‌روزرسانی برنامه و بارگذاری گزارش‌ها
WorkManager روشی برای زمان‌بندی کارهای دوره‌ای حساس به زمان ارائه می‌دهد. می‌توانید فاصله تکرار و flexInterval (حداقل ۱۵ دقیقه) را برای تعریف زمان اجرای دقیق کار ارائه دهید.
کنش مشخص‌شده توسط کاربر که باید پس‌از زمان مشخصی اتفاق بیفتد (حتی اگر سیستم در حالت غیرفعال باشد)
از زنگ ساعت غیردقیق استفاده کنید. به‌طور دقیق، با setAndAllowWhileIdle() تماس بگیرید.
کنش مشخص‌شده ازسوی کاربر که باید بعداز زمان مشخصی اتفاق بیفتد
از زنگ ساعت غیردقیق استفاده کنید. به‌طور دقیق، با set() تماس بگیرید.
کنش مشخص‌شده توسط کاربر که می‌تواند در پنجره زمانی مشخصی اتفاق بیفتد
از زنگ ساعت غیردقیق استفاده کنید. به‌طور دقیق، با setWindow() تماس بگیرید. توجه داشته باشید که اگر برنامه شما Android 12 یا بالاتر را هدف قرار می‌دهد، کوچک‌ترین طول پنجره مجاز ۱۰ دقیقه است.

روش‌های تنظیم هشدار دقیق

برنامه‌تان می‌تواند بااستفاده از یکی از روش‌های زیر، زنگ‌های دقیق تنظیم کند. این روش‌ها به‌گونه‌ای مرتب شده‌اند که روش‌های نزدیک‌تر به پایین فهرست برای کارهای حساس‌تر به زمان هستند اما به منابع سیستم بیشتری نیاز دارند.

setExact()

زنگ هشداری را در زمانی تقریباً دقیق در آینده فراخوانی کنید، به‌شرطی که سایر اقدامات صرفه‌جویی در مصرف باتری فعال نباشند.

از این روش برای تنظیم زنگ‌های دقیق استفاده کنید، مگراینکه کار برنامه‌تان برای کاربر ازنظر زمانی حیاتی باشد.

setExactAndAllowWhileIdle()

زنگ هشداری را در زمانی تقریباً دقیق در آینده فراخوانی کنید، حتی اگر اقدامات صرفه‌جویی در باتری فعال باشد.

setAlarmClock()

زنگ هشداری را در زمان دقیقی در آینده فراخوانی کنید. چون این هشدارها برای کاربران بسیار نمایان است، سیستم هرگز زمان تحویل آن‌ها را تنظیم نمی‌کند. سیستم این هشدارها را به‌عنوان مهم‌ترین هشدارها شناسایی می‌کند و درصورت لزوم، برای ارائه هشدارها از حالت‌های کم‌مصرف خارج می‌شود.

مصرف منابع سیستم

وقتی سیستم زنگ‌های دقیقی را که برنامه‌تان تنظیم کرده است راه‌اندازی می‌کند، دستگاه مقدار زیادی از منابع، مانند عمر باتری، را مصرف می‌کند، به‌ویژه اگر در حالت ذخیره انرژی باشد. علاوه‌براین، سیستم نمی‌تواند به‌راحتی این درخواست‌ها را دسته‌بندی کند تا از منابع به‌طور مؤثرتری استفاده کند.

اکیداً توصیه می‌شود که هر زمان ممکن بود زنگ ساعت غیردقیق ایجاد کنید. برای انجام کارهای طولانی‌تر، آن را بااستفاده از WorkManager یا JobScheduler از BroadcastReceiver زنگ هشدارتان زمان‌بندی کنید. برای انجام کار درحین قرار داشتن دستگاه در حالت «چرت»، بااستفاده از setAndAllowWhileIdle() زنگ ساعت غیردقیقی ایجاد کنید، و کاری را از زنگ ساعت شروع کنید.

اجازه هشدار دقیق مناسب را اعلام کنید

اگر برنامه‌تان Android نسخه ۱۲ یا بالاتر را هدف قرار می‌دهد، باید دسترسی ویژه برنامه «زنگ‌های ساعت و یادآوری‌ها» را دریافت کنید. برای انجام این کار، اجازه SCHEDULE_EXACT_ALARM را در فایل مانیفست برنامه‌تان اعلام کنید، همان‌طور که در تکه‌کد زیر نشان داده شده است:

<manifest ...>
    <uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM"/>
    <application ...>
        ...
    </application>
</manifest>

اگر برنامه شما Android 13 (سطح میانای برنامه‌سازی کاربردی ۳۳) یا بالاتر را هدف قرار می‌دهد، این گزینه را دارید که اجازه SCHEDULE_EXACT_ALARM یا USE_EXACT_ALARM را اعلام کنید.

<manifest ...>
    <uses-permission android:name="android.permission.USE_EXACT_ALARM"/>
    <application ...>
        ...
    </application>
</manifest>

هرچند هر دو اجازه SCHEDULE_EXACT_ALARM و USE_EXACT_ALARM قابلیت‌های یکسانی را نشان می‌دهند، اما به‌طور متفاوتی اعطا می‌شوند و از موارد استفاده متفاوتی پشتیبانی می‌کنند. برنامه شما باید از هشدارهای دقیق استفاده کند و اجازه SCHEDULE_EXACT_ALARM یا USE_EXACT_ALARM را فقط درصورتی اعلام کند که عملکردی سَمت کاربر در برنامه شما به کنش‌هایی با زمان‌بندی دقیق نیاز داشته باشد.

USE_EXACT_ALARM

SCHEDULE_EXACT_ALARM

  • اعطاشده توسط کاربر
  • مجموعه گسترده‌تری از موارد استفاده
  • برنامه‌ها باید تأیید کنند که اجازه لغو نشده است

اجازه SCHEDULE_EXACT_ALARM ازقبل به نصب‌های جدید برنامه‌هایی که Android 13 (سطح میانای برنامه‌سازی کاربردی ۳۳) و بالاتر را هدف قرار می‌دهند اعطا نمی‌شود. اگر کاربری داده‌های برنامه را ازطریق عملیات پشتیبان‌گیری و بازیابی به دستگاهی که Android 14 را اجرا می‌کند منتقل کند، اجازه SCHEDULE_EXACT_ALARM در دستگاه جدید رد خواهد شد. بااین‌حال، اگر برنامه موجودی ازقبل این اجازه را داشته باشد، وقتی دستگاه به Android 14 ارتقا یابد، این اجازه ازقبل اعطا خواهد شد.

توجه: اگر هشدار دقیق بااستفاده از شیء OnAlarmListener تنظیم شده باشد، مثلاً با setExact API، به اجازه SCHEDULE_EXACT_ALARM نیازی نیست.

استفاده از اجازه SCHEDULE_EXACT_ALARM

برخلاف USE_EXACT_ALARM، اجازه SCHEDULE_EXACT_ALARM باید توسط کاربر اعطا شود. هم کاربر و هم سیستم می‌توانند اجازه SCHEDULE_EXACT_ALARM را لغو کنند.

برای بررسی اینکه آیا این اجازه به برنامه شما اعطا شده است یا نه، قبل‌از تلاش برای تنظیم هشدار دقیق، canScheduleExactAlarms() را فراخوانی کنید. وقتی اجازه SCHEDULE_EXACT_ALARM برای برنامه‌تان لغو شود، برنامه‌تان متوقف می‌شود و همه هشدارهای دقیق آینده لغو می‌شوند. این یعنی مقدار برگردانده‌شده توسط canScheduleExactAlarms() برای کل چرخه حیات برنامه‌تان معتبر می‌ماند.

وقتی اجازه SCHEDULE_EXACT_ALARMS به برنامه شما اعطا می‌شود، سیستم ACTION_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED را به آن ارسال می‌کند. برنامه شما باید گیرنده رویداد ثبت‌شده‌ای را پیاده‌سازی کند که کارهای زیر را انجام می‌دهد:

  1. تأیید می‌کند که برنامه‌تان همچنان دسترسی ویژه به برنامه را دارد. برای انجام این کار، با canScheduleExactAlarms() تماس بگیرید. این بررسی از برنامه شما دربرابر موردی محافظت می‌کند که کاربر به برنامه شما اجازه می‌دهد، سپس تقریباً بلافاصله پس‌از آن، آن را لغو می‌کند.
  2. هر هشدار دقیقی را که برنامه‌تان نیاز دارد، براساس وضعیت فعلی آن، دوباره زمان‌بندی می‌کند. این منطق باید مشابه کاری باشد که برنامه‌تان هنگام دریافت همه‌فرستی ACTION_BOOT_COMPLETED انجام می‌دهد.

از کاربران بخواهید اجازه SCHEDULE_EXACT_ALARM را اعطا کنند

این گزینه «مجاز کردن تنظیم زنگ ساعت و یادآوری‌ها» نام دارد
شکل ۱. صفحه دسترسی ویژه برنامه «زنگ‌های ساعت و یادآوری‌ها» در تنظیمات سیستم، که در آن کاربران می‌توانند به برنامه شما اجازه دهند زنگ‌های ساعت دقیق تنظیم کند.

درصورت لزوم، می‌توانید کاربران را به صفحه زنگ‌های ساعت و یادآوری‌ها در تنظیمات سیستم ارسال کنید، همان‌طور که در شکل ۱ نشان داده شده است. برای انجام این کار، مراحل زیر را تکمیل کنید:

  1. در میانای کاربری برنامه‌تان، به کاربر توضیح دهید چرا برنامه‌تان باید زنگ‌های دقیق را زمان‌بندی کند.
  2. قصدی را فراخوانی کنید که شامل کنش قصد ACTION_REQUEST_SCHEDULE_EXACT_ALARM باشد.

تنظیم زنگ ساعت تکرارشونده

زنگ‌های تکرارشونده به سیستم اجازه می‌دهند در زمان‌بندی تکرارشونده به برنامه شما اطلاع دهد.

زنگ هشداری که طراحی ضعیفی داشته باشد می‌تواند باعث تخلیه باتری شود و بار قابل‌توجهی بر سرورها تحمیل کند. به همین دلیل، در Android نسخه ۴.۴ (سطح میانای برنامه‌سازی کاربردی ۱۹) و بالاتر، همه زنگ‌های تکرارشونده زنگ‌های غیردقیق هستند.

زنگ ساعت تکرارشونده ویژگی‌های زیر را دارد:

  • نوع زنگ ساعت. برای بحث بیشتر، به انتخاب نوع هشدار مراجعه کنید.

  • زمان راه‌انداز. اگر زمان راه‌اندازی که مشخص می‌کنید در گذشته باشد، زنگ ساعت فوراً راه‌اندازی می‌شود.

  • فاصله زمانی زنگ ساعت. برای مثال، یک‌بار در روز، هر ساعت، یا هر ۵ دقیقه.

  • قصد معوقی که هنگام فعال شدن زنگ ساعت اجرا می‌شود. وقتی زنگ ساعت دومی تنظیم می‌کنید که از همان قصد معوق استفاده می‌کند، این زنگ ساعت جایگزین زنگ ساعت اصلی می‌شود.

برای لغو کردن PendingIntent()، FLAG_NO_CREATE را به PendingIntent.getService() ارسال کنید تا نمونه‌ای از هدف (درصورت وجود) دریافت کنید، سپس آن هدف را به AlarmManager.cancel() ارسال کنید

کاتلین

val alarmManager =
    context.getSystemService(Context.ALARM_SERVICE) as? AlarmManager
val pendingIntent =
    PendingIntent.getService(context, requestId, intent,
                                PendingIntent.FLAG_NO_CREATE)
if (pendingIntent != null && alarmManager != null) {
  alarmManager.cancel(pendingIntent)
}

جاوا

AlarmManager alarmManager =
    (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
PendingIntent pendingIntent =
    PendingIntent.getService(context, requestId, intent,
                                PendingIntent.FLAG_NO_CREATE);
if (pendingIntent != null && alarmManager != null) {
  alarmManager.cancel(pendingIntent);
}

انتخاب نوع زنگ ساعت

یکی از اولین ملاحظات در استفاده از زنگ ساعت تکرارشونده این است که نوع آن چه باید باشد.

دو نوع ساعت کلی برای هشدارها وجود دارد: «زمان واقعی سپری‌شده» و «ساعت زمان واقعی» (RTC). زمان واقعی سپری‌شده از «زمان پس‌از راه‌اندازی سیستم» به‌عنوان مرجع استفاده می‌کند، و ساعت زمان واقعی از زمان UTC (ساعت دیواری) استفاده می‌کند. این یعنی زمان واقعی سپری‌شده برای تنظیم زنگ هشدار براساس گذر زمان مناسب است (برای مثال، زنگ هشداری که هر ۳۰ ثانیه به‌صدا درمی‌آید) زیرا تحت تأثیر منطقه زمانی یا منطقه زبانی قرار نمی‌گیرد. نوع ساعت زمان واقعی برای زنگ‌های ساعتی که به زبان محلی فعلی وابسته هستند مناسب‌تر است.

هر دو نوع دارای نسخه «بیدارباش» هستند که می‌گوید اگر صفحه‌نمایش خاموش است، واحد پردازش مرکزی دستگاه را بیدار کند. این کار تضمین می‌کند که زنگ ساعت در زمان زمان‌بندی‌شده به‌صدا درآید. این کار زمانی مفید است که برنامه‌تان وابستگی زمانی داشته باشد. برای مثال، اگر پنجره محدودی برای انجام عملیات خاصی داشته باشد. اگر از نسخه بیدارباش نوع زنگ هشدارتان استفاده نکنید، همه زنگ‌های هشدار تکرارشونده وقتی دستگاهتان دفعه بعد بیدار شود به‌صدا درمی‌آیند.

اگر فقط می‌خواهید زنگ ساعتتان در بازه زمانی خاصی (مثلاً هر نیم ساعت) به‌صدا درآید، از یکی از انواع زمان واقعی سپری‌شده استفاده کنید. به‌طور کلی، این انتخاب بهتری است.

اگر لازم است زنگ ساعت در زمان خاصی از روز به‌صدا درآید، یکی از انواع ساعت‌های زمان واقعی مبتنی بر ساعت را انتخاب کنید. اما توجه داشته باشید که این رویکرد می‌تواند معایبی داشته باشد. ممکن است برنامه به‌خوبی به زبان‌های دیگر ترجمه نشود و اگر کاربر تنظیمات زمان دستگاه را تغییر دهد، می‌تواند باعث رفتار غیرمنتظره در برنامه‌تان شود. استفاده از نوع هشدار ساعت زمان واقعی نیز به‌خوبی مقیاس‌بندی نمی‌شود، همان‌طور که در بالا بحث شد. توصیه می‌کنیم درصورت امکان از زنگ هشدار «زمان واقعی سپری‌شده» استفاده کنید.

فهرست انواع در اینجا آمده است:

  • ELAPSED_REALTIME: قصد معوق را براساس مدت زمانی که از راه‌اندازی دستگاه گذشته است فعال می‌کند، اما دستگاه را بیدار نمی‌کند. زمان سپری‌شده شامل هر زمانی است که دستگاه در حالت خواب بوده است.

  • ELAPSED_REALTIME_WAKEUP: دستگاه را بیدار می‌کند و قصد معوق را پس‌از سپری شدن مدت زمان مشخص‌شده از راه‌اندازی دستگاه اجرا می‌کند.

  • RTC: قصد معوق را در زمان مشخص‌شده اجرا می‌کند اما دستگاه را بیدار نمی‌کند.

  • RTC_WAKEUP: دستگاه را بیدار می‌کند تا قصد معوق را در زمان مشخص‌شده اجرا کند.

نمونه‌هایی از زنگ‌های ساعت زمان واقعی سپری‌شده

در اینجا چند نمونه از استفاده از ELAPSED_REALTIME_WAKEUP آورده شده است

دستگاه را بیدار کنید تا زنگ ساعت ۳۰ دقیقه دیگر و هر ۳۰ دقیقه پس‌از آن به‌صدا درآید:

کاتلین

// Hopefully your alarm will have a lower frequency than this!
alarmMgr?.setInexactRepeating(
        AlarmManager.ELAPSED_REALTIME_WAKEUP,
        SystemClock.elapsedRealtime() + AlarmManager.INTERVAL_HALF_HOUR,
        AlarmManager.INTERVAL_HALF_HOUR,
        alarmIntent
)

جاوا

// Hopefully your alarm will have a lower frequency than this!
alarmMgr.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
        SystemClock.elapsedRealtime() + AlarmManager.INTERVAL_HALF_HOUR,
        AlarmManager.INTERVAL_HALF_HOUR, alarmIntent);

دستگاه را بیدار کنید تا زنگ ساعت یک‌باره (غیرتکراری) در یک دقیقه به‌صدا درآید:

کاتلین

private var alarmMgr: AlarmManager? = null
private lateinit var alarmIntent: PendingIntent
...
alarmMgr = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
alarmIntent = Intent(context, AlarmReceiver::class.java).let { intent ->
    PendingIntent.getBroadcast(context, 0, intent, 0)
}

alarmMgr?.set(
        AlarmManager.ELAPSED_REALTIME_WAKEUP,
        SystemClock.elapsedRealtime() + 60 * 1000,
        alarmIntent
)

جاوا

private AlarmManager alarmMgr;
private PendingIntent alarmIntent;
...
alarmMgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, AlarmReceiver.class);
alarmIntent = PendingIntent.getBroadcast(context, 0, intent, 0);

alarmMgr.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
        SystemClock.elapsedRealtime() +
        60 * 1000, alarmIntent);

نمونه‌هایی از زنگ‌های ساعت بی‌درنگ

در اینجا چند نمونه از استفاده از RTC_WAKEUP آورده شده است.

دستگاه را بیدار کنید تا زنگ ساعت تقریباً ساعت ۲:۰۰ ب.ظ. به‌صدا درآید، و یک‌بار در روز در همان زمان تکرار شود:

کاتلین

// Set the alarm to start at approximately 2:00 p.m.
val calendar: Calendar = Calendar.getInstance().apply {
    timeInMillis = System.currentTimeMillis()
    set(Calendar.HOUR_OF_DAY, 14)
}

// With setInexactRepeating(), you have to use one of the AlarmManager interval
// constants--in this case, AlarmManager.INTERVAL_DAY.
alarmMgr?.setInexactRepeating(
        AlarmManager.RTC_WAKEUP,
        calendar.timeInMillis,
        AlarmManager.INTERVAL_DAY,
        alarmIntent
)

جاوا

// Set the alarm to start at approximately 2:00 p.m.
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, 14);

// With setInexactRepeating(), you have to use one of the AlarmManager interval
// constants--in this case, AlarmManager.INTERVAL_DAY.
alarmMgr.setInexactRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
        AlarmManager.INTERVAL_DAY, alarmIntent);

دستگاه را فعال کنید تا زنگ ساعت دقیقاً در ساعت ۸:۳۰ صبح و هر ۲۰ دقیقه پس‌از آن به‌صدا درآید:

کاتلین

private var alarmMgr: AlarmManager? = null
private lateinit var alarmIntent: PendingIntent
...
alarmMgr = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
alarmIntent = Intent(context, AlarmReceiver::class.java).let { intent ->
    PendingIntent.getBroadcast(context, 0, intent, 0)
}

// Set the alarm to start at 8:30 a.m.
val calendar: Calendar = Calendar.getInstance().apply {
    timeInMillis = System.currentTimeMillis()
    set(Calendar.HOUR_OF_DAY, 8)
    set(Calendar.MINUTE, 30)
}

// setRepeating() lets you specify a precise custom interval--in this case,
// 20 minutes.
alarmMgr?.setRepeating(
        AlarmManager.RTC_WAKEUP,
        calendar.timeInMillis,
        1000 * 60 * 20,
        alarmIntent
)

جاوا

private AlarmManager alarmMgr;
private PendingIntent alarmIntent;
...
alarmMgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, AlarmReceiver.class);
alarmIntent = PendingIntent.getBroadcast(context, 0, intent, 0);

// Set the alarm to start at 8:30 a.m.
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, 8);
calendar.set(Calendar.MINUTE, 30);

// setRepeating() lets you specify a precise custom interval--in this case,
// 20 minutes.
alarmMgr.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
        1000 * 60 * 20, alarmIntent);

تصمیم بگیرید زنگ ساعتتان چقدر باید دقیق باشد

همان‌طور که قبلاً توضیح داده شد، انتخاب نوع زنگ ساعت اغلب اولین مرحله در ایجاد زنگ ساعت است. تفاوت دیگر این است که می‌خواهید زنگ ساعتتان چقدر دقیق باشد. برای اکثر برنامه‌ها، setInexactRepeating() انتخاب مناسبی است. وقتی از این روش استفاده می‌کنید، Android چندین زنگ هشدار تکرارشونده غیردقیق را همگام‌سازی می‌کند و آن‌ها را به‌طور هم‌زمان به‌صدا درمی‌آورد. این کار مصرف باتری را کاهش می‌دهد.

درصورت امکان، از هشدارهای دقیق استفاده نکنید. بااین‌حال، برای برنامه‌های نادری که الزامات زمانی سخت‌گیرانه‌ای دارند، می‌توانید با فراخوانی setRepeating()، زنگ ساعت دقیق تنظیم کنید.

با setInexactRepeating()، نمی‌توانید فاصله سفارشی را به روشی که با setRepeating() می‌توانید مشخص کنید. باید از یکی از ثابت‌های بازه استفاده کنید، مثل INTERVAL_FIFTEEN_MINUTES، INTERVAL_DAY، و غیره. برای دیدن فهرست کامل، به AlarmManager بروید.

لغو زنگ ساعت

بسته به برنامه‌تان، ممکن است بخواهید قابلیت لغو زنگ ساعت را اضافه کنید. برای لغو زنگ ساعت، cancel() را در «مدیر زنگ ساعت» فراخوانی کنید و PendingIntent را که دیگر نمی‌خواهید به‌صدا درآید ارسال کنید. برای مثال:

کاتلین

// If the alarm has been set, cancel it.
alarmMgr?.cancel(alarmIntent)

جاوا

// If the alarm has been set, cancel it.
if (alarmMgr!= null) {
    alarmMgr.cancel(alarmIntent);
}

هنگام بازراه‌اندازی دستگاه، زنگ ساعت شروع شود

به‌طور پیش‌فرض، وقتی دستگاه خاموش می‌شود، همه زنگ‌های ساعت لغو می‌شوند. برای جلوگیری از این اتفاق، می‌توانید برنامه‌تان را طوری طراحی کنید که اگر کاربر دستگاه را بازراه‌اندازی کرد، زنگ تکرارشونده به‌طور خودکار بازراه‌اندازی شود. این کار تضمین می‌کند که AlarmManager به انجام وظیفه خود ادامه دهد بدون اینکه کاربر نیاز داشته باشد زنگ ساعت را به‌طور دستی بازراه‌اندازی کند.

مراحل مربوطه در اینجا آمده است:

  1. اجازه RECEIVE_BOOT_COMPLETED را در مانیفست برنامه‌تان تنظیم کنید. این به برنامه شما اجازه می‌دهد ACTION_BOOT_COMPLETED را که پس‌از پایان راه‌اندازی سیستم پخش می‌شود دریافت کند (این فقط درصورتی کار می‌کند که برنامه قبلاً حداقل یک‌بار توسط کاربر راه‌اندازی شده باشد):

    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
  2. یک BroadcastReceiver را برای دریافت همه‌فرستی پیاده‌سازی کنید:

    کاتلین

    class SampleBootReceiver : BroadcastReceiver() {
    
        override fun onReceive(context: Context, intent: Intent) {
            if (intent.action == "android.intent.action.BOOT_COMPLETED") {
                // Set the alarm here.
            }
        }
    }

    جاوا

    public class SampleBootReceiver extends BroadcastReceiver {
    
        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent.getAction().equals("android.intent.action.BOOT_COMPLETED")) {
                // Set the alarm here.
            }
        }
    }
  3. گیرنده را با فیلتر هدفی که روی کنش ACTION_BOOT_COMPLETED فیلتر می‌کند به فایل مانیفست برنامه‌تان اضافه کنید:

    <receiver android:name=".SampleBootReceiver"
            android:enabled="false">
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED"></action>
        </intent-filter>
    </receiver>

    توجه داشته باشید که در مانیفست، گیرنده راه‌اندازی روی android:enabled="false" تنظیم شده است. این یعنی گیرنده فراخوانی نخواهد شد مگر اینکه برنامه به‌طور صریح آن را فعال کند. این کار از فراخوانی غیرضروری گیرنده راه‌اندازی جلوگیری می‌کند. می‌توانید گیرنده‌ای را (برای مثال، اگر کاربر زنگ ساعتی تنظیم کند) به‌صورت زیر فعال کنید:

    کاتلین

    val receiver = ComponentName(context, SampleBootReceiver::class.java)
    
    context.packageManager.setComponentEnabledSetting(
            receiver,
            PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
            PackageManager.DONT_KILL_APP
    )

    جاوا

    ComponentName receiver = new ComponentName(context, SampleBootReceiver.class);
    PackageManager pm = context.getPackageManager();
    
    pm.setComponentEnabledSetting(receiver,
            PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
            PackageManager.DONT_KILL_APP);

    وقتی گیرنده را از این طریق فعال کنید، فعال باقی می‌ماند، حتی اگر کاربر دستگاه را بازراه‌اندازی کند. به‌عبارت دیگر، فعال کردن گیرنده به‌صورت برنامه‌نویسی‌شده تنظیم مانیفست را لغو می‌کند، حتی در بازراه‌اندازی‌ها. گیرنده تا زمانی که برنامه‌تان آن را غیرفعال نکند، فعال باقی خواهد ماند. می‌توانید گیرنده را به‌صورت زیر غیرفعال کنید (برای مثال، اگر کاربر زنگ ساعتی را لغو کند):

    کاتلین

    val receiver = ComponentName(context, SampleBootReceiver::class.java)
    
    context.packageManager.setComponentEnabledSetting(
            receiver,
            PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
            PackageManager.DONT_KILL_APP
    )

    جاوا

    ComponentName receiver = new ComponentName(context, SampleBootReceiver.class);
    PackageManager pm = context.getPackageManager();
    
    pm.setComponentEnabledSetting(receiver,
            PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
            PackageManager.DONT_KILL_APP);

فراخوانی هشدارها وقتی دستگاه در حالت «چرت زدن» است

دستگاه‌هایی که Android نسخه ۶.۰ (سطح میانای برنامه‌سازی کاربردی ۲۳) را اجرا می‌کنند از حالت چرت زدن پشتیبانی می‌کنند که به افزایش عمر باتری دستگاه کمک می‌کند. وقتی دستگاه در حالت چرت زدن باشد، زنگ‌های ساعت به‌صدا درنمی‌آیند هر زنگ ساعت زمان‌بندی‌شده‌ای تا زمانی که دستگاه از «حالت چرت زدن» خارج شود به‌تعویق می‌افتد. اگر لازم است کار را حتی وقتی دستگاه غیرفعال است تکمیل کنید، چند گزینه دردسترس است:

  • هشدار دقیق تنظیم کنید.

  • از WorkManager API استفاده کنید که برای انجام کار پس‌زمینه‌ای ساخته شده است. می‌توانید مشخص کنید که سیستم باید کار شما را تسریع کند تا کار در اسرع وقت تمام شود. برای اطلاعات بیشتر، به زمان‌بندی تکالیف با WorkManager مراجعه کنید

روال‌های مطلوب

هر انتخابی که در طراحی زنگ ساعت تکرارشونده خود می‌کنید می‌تواند پیامدهایی در نحوه استفاده (یا سوءاستفاده) برنامه شما از منابع سیستم داشته باشد. برای مثال، برنامه محبوبی را تصور کنید که با سرور همگام‌سازی می‌شود. اگر عملیات همگام‌سازی براساس زمان ساعت باشد و هر نمونه از برنامه در ساعت ۱۱:۰۰ شب همگام‌سازی شود، بار روی سرور می‌تواند منجر به تأخیر زیاد یا حتی «ممانعت از سرویس» شود. این روال‌های مطلوب را برای استفاده از زنگ‌های ساعت دنبال کنید:

  • به هر درخواست شبکه‌ای که درنتیجه زنگ هشدار تکراری راه‌اندازی می‌شود، تصادفی بودن (لرزش) اضافه کنید:

    • هنگام به‌صدا درآمدن زنگ ساعت، هرگونه کار محلی را انجام دهید. «کار محلی» یعنی هر چیزی که به سرور نمی‌رسد یا به داده‌های سرور نیاز ندارد.

    • هم‌زمان، زنگ هشداری را که حاوی درخواست‌های شبکه است زمان‌بندی کنید تا در یک دوره زمانی تصادفی فعال شود.

  • بسامد زنگ ساعت را در حداقل نگه دارید.

  • دستگاه را بی‌دلیل بیدار نکنید (این رفتار براساس نوع زنگ ساعت تعیین می‌شود، همان‌طور که در انتخاب نوع زنگ ساعت شرح داده شده است).

  • زمان راه‌اندازی زنگ هشدار را دقیق‌تر از آنچه باید باشد تنظیم نکنید.

    از setInexactRepeating() به‌جای setRepeating() استفاده کنید. وقتی از setInexactRepeating() استفاده می‌کنید، Android زنگ‌های تکرارشونده را از چند برنامه همگام‌سازی می‌کند و آن‌ها را به‌طور هم‌زمان به‌صدا درمی‌آورد. این کار تعداد دفعاتی را که سیستم باید دستگاه را بیدار کند کاهش می‌دهد، بنابراین مصرف باتری کاهش می‌یابد. از Android 4.4 (میانای برنامه‌سازی کاربردی سطح ۱۹)، همه زنگ‌های تکرارشونده زنگ غیردقیق هستند. توجه داشته باشید که اگرچه setInexactRepeating() بهبودی نسبت‌به setRepeating() است، اما اگر هر نمونه از برنامه تقریباً هم‌زمان به سرور دسترسی پیدا کند، همچنان می‌تواند سرور را تحت‌فشار قرار دهد. بنابراین، برای درخواست‌های شبکه، همان‌طور که قبلاً بحث شد، کمی تصادفی‌سازی به زنگ‌هایتان اضافه کنید.

  • درصورت امکان، از تنظیم زنگ ساعت براساس زمان ساعت خودداری کنید.

    زنگ‌های ساعت تکرارشونده که براساس زمان راه‌انداز دقیق هستند به‌خوبی مقیاس‌بندی نمی‌شوند. درصورت امکان، از ELAPSED_REALTIME استفاده کنید. انواع مختلف زنگ ساعت با جزئیات بیشتر در بخش زیر شرح داده شده است.