آلارم ها را برنامه ریزی کنید

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

آلارم ها این ویژگی ها را دارند:

  • آنها به شما اجازه می دهند Intent ها را در زمان ها و/یا فواصل تعیین شده شلیک کنید.

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

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

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

یک زنگ هشدار غیر دقیق تنظیم کنید

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

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

بعد از یک زمان مشخص زنگ هشدار را تحویل دهید

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

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

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

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

اگر برنامه شما Android 12 یا بالاتر را هدف قرار می دهد، سیستم می تواند فراخوانی زنگ هشدار نادرست پنجره زمانی را حداقل 10 دقیقه به تاخیر بیاندازد. به همین دلیل، مقادیر پارامتر windowLengthMillis زیر 600000 به 600000 بریده می شود.

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

اگر برنامه شما setInexactRepeating() فراخوانی کند، سیستم چندین آلارم را فراخوانی می کند:

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

یک زنگ دقیق تنظیم کنید

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

بیشتر برنامه‌ها می‌توانند وظایف و رویدادها را با استفاده از آلارم‌های غیردقیق برای تکمیل چندین مورد استفاده معمول زمان‌بندی کنند. اگر عملکرد اصلی برنامه شما به زنگ هشداری با زمان دقیق بستگی دارد - مانند یک برنامه ساعت زنگ دار یا یک برنامه تقویم - پس اشکالی ندارد که به جای آن از یک زنگ دقیق استفاده کنید.

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

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

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

راه های تنظیم زنگ دقیق

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

setExact()

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

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

setExactAndAllowWhileIdle()

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

setAlarmClock()

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

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

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

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

مجوز دقیق زنگ هشدار را اعلام کنید

اگر برنامه شما Android 12 یا بالاتر را هدف قرار می‌دهد، باید دسترسی ویژه برنامه "Alarms & Reymmers" را دریافت کنید. برای انجام این کار، همانطور که در قطعه کد زیر نشان داده شده است، مجوز SCHEDULE_EXACT_ALARM را در فایل مانیفست برنامه خود اعلام کنید:

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

اگر برنامه شما Android 13 (سطح API 33) یا بالاتر را هدف قرار می‌دهد، می‌توانید مجوز 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 (سطح API 33) و بالاتر را هدف قرار می‌دهند، اعطا نمی‌شود. اگر کاربر از طریق عملیات پشتیبان‌گیری و بازیابی، داده‌های برنامه را به دستگاه دارای Android 14 منتقل کند، مجوز SCHEDULE_EXACT_ALARM در دستگاه جدید رد می‌شود. با این حال، اگر یک برنامه موجود از قبل این مجوز را داشته باشد، زمانی که دستگاه به اندروید 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. صفحه دسترسی ویژه برنامه "زنگ هشدار و یادآوری" در تنظیمات سیستم، که در آن کاربران می توانند به برنامه شما اجازه دهند تا آلارم های دقیق را تنظیم کند.

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

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

یک زنگ تکراری تنظیم کنید

هشدارهای مکرر به سیستم این امکان را می دهد که برنامه شما را در یک برنامه تکراری مطلع کند.

یک آلارم با طراحی ضعیف می تواند باعث تخلیه باتری شود و بار قابل توجهی را روی سرورها وارد کند. به همین دلیل، در اندروید 4.4 (سطح API 19) و بالاتر، همه آلارم‌های تکراری آلارم‌های غیردقیق هستند.

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

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

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

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

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

برای لغو یک PendingIntent() ، FLAG_NO_CREATE به PendingIntent.getService() ارسال کنید تا نمونه ای از intent (در صورت وجود) دریافت شود، سپس آن intent را به 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 (ساعت دیواری) استفاده می کند. این بدان معنی است که زمان واقعی سپری شده برای تنظیم زنگ هشدار بر اساس گذر زمان مناسب است (مثلاً زنگ هشداری که هر 30 ثانیه یکبار پخش می شود) زیرا تحت تأثیر منطقه زمانی یا منطقه قرار نمی گیرد. نوع ساعت زمان واقعی برای آلارم هایی که به منطقه فعلی وابسته هستند، مناسب تر است.

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

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

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

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

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

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

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

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

نمونه هایی از آلارم های زمان واقعی سپری شده

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

دستگاه را بیدار کنید تا زنگ هشدار را در 30 دقیقه و هر 30 دقیقه پس از آن روشن شود:

کاتلین

// 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 آورده شده است.

دستگاه را بیدار کنید تا زنگ ساعت تقریباً ساعت 2 بعد از ظهر روشن شود و یک بار در روز در همان زمان تکرار کنید:

کاتلین

// 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);

دستگاه را بیدار کنید تا زنگ ساعت دقیقاً در ساعت 8:30 صبح روشن شود و پس از آن هر 20 دقیقه:

کاتلین

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() انتخاب مناسبی است. هنگامی که از این روش استفاده می کنید، اندروید چندین آلارم تکرار شونده غیردقیق را همگام می کند و آنها را به طور همزمان فعال می کند. این باعث کاهش تخلیه باتری می شود.

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

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

زنگ هشدار را لغو کنید

بسته به برنامه شما، ممکن است بخواهید قابلیت لغو زنگ هشدار را نیز در نظر بگیرید. برای لغو زنگ هشدار، cancel() در Alarm Manager فراخوانی کنید و در 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. گیرنده را به فایل مانیفست برنامه خود با یک فیلتر intent اضافه کنید که عملکرد 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);

هنگامی که دستگاه در حالت Doze است، آلارم ها را فراخوانی کنید

دستگاه‌هایی که دارای Android 6.0 (سطح API 23) هستند، از حالت Doze پشتیبانی می‌کنند که به افزایش عمر باتری دستگاه کمک می‌کند. هنگامی که دستگاه در حالت Doze است، زنگ هشدار روشن نمی شود. هر گونه زنگ هشدار برنامه ریزی شده تا زمانی که دستگاه از Doze خارج شود به تعویق می افتد. اگر نیاز به تکمیل کار دارید حتی زمانی که دستگاه بیکار است، چندین گزینه در دسترس است:

  • یک زنگ دقیق تنظیم کنید.

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

بهترین شیوه ها

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

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

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

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

  • فرکانس آلارم خود را به حداقل برسانید.

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

  • زمان ماشه زنگ خود را دقیق تر از آنچه باید باشد، نکنید.

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

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

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

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

آلارم ها این ویژگی ها را دارند:

  • آنها به شما اجازه می دهند Intent ها را در زمان ها و/یا فواصل تعیین شده شلیک کنید.

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

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

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

یک زنگ هشدار غیر دقیق تنظیم کنید

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

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

بعد از یک زمان مشخص زنگ هشدار را تحویل دهید

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

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

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

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

اگر برنامه شما Android 12 یا بالاتر را هدف قرار می دهد، سیستم می تواند فراخوانی زنگ هشدار نادرست پنجره زمانی را حداقل 10 دقیقه به تاخیر بیاندازد. به همین دلیل، مقادیر پارامتر windowLengthMillis زیر 600000 به 600000 بریده می شود.

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

اگر برنامه شما setInexactRepeating() فراخوانی کند، سیستم چندین آلارم را فراخوانی می کند:

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

یک زنگ دقیق تنظیم کنید

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

بیشتر برنامه‌ها می‌توانند وظایف و رویدادها را با استفاده از آلارم‌های غیردقیق برای تکمیل چندین مورد استفاده معمول زمان‌بندی کنند. اگر عملکرد اصلی برنامه شما به زنگ هشداری با زمان دقیق بستگی دارد - مانند یک برنامه ساعت زنگ دار یا یک برنامه تقویم - پس اشکالی ندارد که به جای آن از یک زنگ دقیق استفاده کنید.

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

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

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

راه های تنظیم زنگ دقیق

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

setExact()

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

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

setExactAndAllowWhileIdle()

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

setAlarmClock()

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

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

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

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

مجوز دقیق زنگ هشدار را اعلام کنید

اگر برنامه شما Android 12 یا بالاتر را هدف قرار می‌دهد، باید دسترسی ویژه برنامه "Alarms & Reymmers" را دریافت کنید. برای انجام این کار، همانطور که در قطعه کد زیر نشان داده شده است، مجوز SCHEDULE_EXACT_ALARM را در فایل مانیفست برنامه خود اعلام کنید:

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

اگر برنامه شما Android 13 (سطح API 33) یا بالاتر را هدف قرار می‌دهد، می‌توانید مجوز 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 (سطح API 33) و بالاتر را هدف قرار می‌دهند، اعطا نمی‌شود. اگر کاربر از طریق عملیات پشتیبان‌گیری و بازیابی، داده‌های برنامه را به دستگاه دارای Android 14 منتقل کند، مجوز SCHEDULE_EXACT_ALARM در دستگاه جدید رد می‌شود. با این حال، اگر یک برنامه موجود از قبل این مجوز را داشته باشد، زمانی که دستگاه به اندروید 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. صفحه دسترسی ویژه برنامه "زنگ هشدار و یادآوری" در تنظیمات سیستم، که در آن کاربران می توانند به برنامه شما اجازه دهند تا آلارم های دقیق را تنظیم کند.

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

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

یک زنگ تکراری تنظیم کنید

هشدارهای مکرر به سیستم این امکان را می دهد که برنامه شما را در یک برنامه تکراری مطلع کند.

یک آلارم با طراحی ضعیف می تواند باعث تخلیه باتری شود و بار قابل توجهی را روی سرورها وارد کند. به همین دلیل، در اندروید 4.4 (سطح API 19) و بالاتر، همه آلارم‌های تکراری آلارم‌های غیردقیق هستند.

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

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

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

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

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

برای لغو یک PendingIntent() ، FLAG_NO_CREATE به PendingIntent.getService() ارسال کنید تا نمونه ای از intent (در صورت وجود) دریافت شود، سپس آن intent را به 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 (ساعت دیواری) استفاده می کند. این بدان معنی است که زمان واقعی سپری شده برای تنظیم زنگ هشدار بر اساس گذر زمان مناسب است (مثلاً زنگ هشداری که هر 30 ثانیه یکبار پخش می شود) زیرا تحت تأثیر منطقه زمانی یا منطقه قرار نمی گیرد. نوع ساعت زمان واقعی برای آلارم هایی که به منطقه فعلی وابسته هستند، مناسب تر است.

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

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

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

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

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

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

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

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

نمونه هایی از آلارم های زمان واقعی سپری شده

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

دستگاه را بیدار کنید تا زنگ هشدار را در 30 دقیقه و هر 30 دقیقه پس از آن روشن شود:

کاتلین

// 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 آورده شده است.

دستگاه را بیدار کنید تا زنگ ساعت تقریباً ساعت 2 بعد از ظهر روشن شود و یک بار در روز در همان زمان تکرار کنید:

کاتلین

// 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);

دستگاه را بیدار کنید تا زنگ ساعت دقیقاً در ساعت 8:30 صبح روشن شود و پس از آن هر 20 دقیقه:

کاتلین

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() انتخاب مناسبی است. هنگامی که از این روش استفاده می کنید، اندروید چندین آلارم تکرار شونده غیردقیق را همگام می کند و آنها را به طور همزمان فعال می کند. این باعث کاهش تخلیه باتری می شود.

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

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

زنگ هشدار را لغو کنید

بسته به برنامه شما، ممکن است بخواهید قابلیت لغو زنگ هشدار را نیز در نظر بگیرید. برای لغو زنگ هشدار، cancel() در Alarm Manager فراخوانی کنید و در 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. گیرنده را به فایل مانیفست برنامه خود با یک فیلتر intent اضافه کنید که عملکرد 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);

هنگامی که دستگاه در حالت Doze است، آلارم ها را فراخوانی کنید

دستگاه‌هایی که دارای Android 6.0 (سطح API 23) هستند، از حالت Doze پشتیبانی می‌کنند که به افزایش عمر باتری دستگاه کمک می‌کند. هنگامی که دستگاه در حالت Doze است، زنگ هشدار روشن نمی شود. هر گونه زنگ هشدار برنامه ریزی شده تا زمانی که دستگاه از Doze خارج شود به تعویق می افتد. اگر نیاز به تکمیل کار دارید حتی زمانی که دستگاه بیکار است، چندین گزینه در دسترس است:

  • یک زنگ دقیق تنظیم کنید.

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

بهترین شیوه ها

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

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

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

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

  • فرکانس آلارم خود را به حداقل برسانید.

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

  • زمان ماشه زنگ خود را دقیق تر از آنچه باید باشد، نکنید.

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

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

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