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

آلارم ها (بر اساس کلاس 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:00 بعد از ظهر آتش بزنید و یک بار در روز همزمان تکرار کنید:

کاتلین

// 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() انتخاب درستی است. هنگامی که از این روش استفاده می کنید ، 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);

در حالی که دستگاه در حالت Doze است ، از هشدار استفاده کنید

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

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

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

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

هر انتخابی که در طراحی هشدار مکرر خود ایجاد می کنید می تواند در نحوه استفاده از برنامه (یا سوء استفاده از برنامه شما) از منابع سیستم عواقب داشته باشد. به عنوان مثال ، یک برنامه محبوب را تصور کنید که با یک سرور همگام سازی می شود. اگر عملکرد همگام سازی بر اساس زمان ساعت و هر نمونه از برنامه ها در ساعت 11 بعد از ظهر باشد ، بار در سرور می تواند منجر به تأخیر زیاد یا حتی "انکار سرویس" شود. این بهترین روشها را در استفاده از هشدارها دنبال کنید:

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

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

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

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

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

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

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

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

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

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

هشدارها این خصوصیات را دارند:

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

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

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

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

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

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

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

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

اگر برنامه شما set() ، setInexactRepeating() یا setAndAllowWhileIdle() را تنظیم کند ، زنگ هشدار هرگز قبل از زمان ماشه تأمین شده خاموش نمی شود.

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

در یک پنجره زمانی زنگ هشدار را تحویل دهید

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

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

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

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

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

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

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

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

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

لیست زیر گردش کار متداول را نشان می دهد که ممکن است نیاز به زنگ دقیق نداشته باشد:

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

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

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

setExact()

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

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

setExactAndAllowWhileIdle()

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

setAlarmClock()

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

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

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

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

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

اگر برنامه شما Android 12 یا بالاتر را هدف قرار داده است ، باید دسترسی برنامه ویژه "هشدارها و یادآوری ها" را بدست آورید. برای انجام این کار ، مجوز 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 در دستگاه جدید رد می شود. با این حال ، اگر یک برنامه موجود از قبل این مجوز را داشته باشد ، وقتی دستگاه به Android 14 ارتقا می یابد ، از قبل اعطا می شود.

توجه : اگر زنگ دقیق با استفاده از یک شیء OnAlarmListener تنظیم شده است ، مانند API setExact ، مجوز 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. در UI برنامه خود ، به کاربر توضیح دهید که چرا برنامه شما نیاز به برنامه ریزی هشدارهای دقیق دارد.
  2. از یک هدف استفاده کنید که شامل عمل ACTION_REQUEST_SCHEDULE_EXACT_ALARM است.

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

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

زنگ خطرناک می تواند باعث تخلیه باتری شود و بار قابل توجهی را روی سرورها قرار دهد. به همین دلیل ، در Android 4.4 (سطح API 19) و بالاتر ، همه آلارم های تکرار شونده آلارم های ناچیز هستند.

زنگ هشدار مکرر ویژگی های زیر را دارد:

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

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

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

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

برای لغو یک 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). Elaped Real Time از "زمان از زمان بوت سیستم" به عنوان مرجع استفاده می کند و ساعت زمان واقعی از زمان 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:00 بعد از ظهر آتش بزنید و یک بار در روز همزمان تکرار کنید:

کاتلین

// 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() انتخاب درستی است. هنگامی که از این روش استفاده می کنید ، 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);

در حالی که دستگاه در حالت Doze است ، از هشدار استفاده کنید

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

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

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

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

هر انتخابی که در طراحی هشدار مکرر خود ایجاد می کنید می تواند در نحوه استفاده از برنامه (یا سوء استفاده از برنامه شما) از منابع سیستم عواقب داشته باشد. به عنوان مثال ، یک برنامه محبوب را تصور کنید که با یک سرور همگام سازی می شود. اگر عملکرد همگام سازی بر اساس زمان ساعت و هر نمونه از برنامه ها در ساعت 11 بعد از ظهر باشد ، بار در سرور می تواند منجر به تأخیر زیاد یا حتی "انکار سرویس" شود. این بهترین روشها را در استفاده از هشدارها دنبال کنید:

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

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

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

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

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

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

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

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

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

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

هشدارها این خصوصیات را دارند:

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

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

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

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

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

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

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

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

اگر برنامه شما set() ، setInexactRepeating() یا setAndAllowWhileIdle() را تنظیم کند ، زنگ هشدار هرگز قبل از زمان ماشه تأمین شده خاموش نمی شود.

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

در یک پنجره زمانی زنگ هشدار را تحویل دهید

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

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

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

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

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

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

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

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

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

لیست زیر گردش کار متداول را نشان می دهد که ممکن است نیاز به زنگ دقیق نداشته باشد:

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

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

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

setExact()

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

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

setExactAndAllowWhileIdle()

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

setAlarmClock()

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

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

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

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

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

اگر برنامه شما Android 12 یا بالاتر را هدف قرار داده است ، باید دسترسی برنامه ویژه "هشدارها و یادآوری ها" را بدست آورید. برای انجام این کار ، مجوز 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) و بالاتر از قبل اعطا نشده است. If a user transfers app data to a device running Android 14 through a backup-and-restore operation, the SCHEDULE_EXACT_ALARM permission will be denied on the new device. However, if an existing app already has this permission, it will be pre-granted when the device upgrades to Android 14.

Note : If the exact alarm is set using an OnAlarmListener object, such as with the setExact API, the SCHEDULE_EXACT_ALARM permission isn't required.

Using the SCHEDULE_EXACT_ALARM permission

Unlike USE_EXACT_ALARM , the SCHEDULE_EXACT_ALARM permission must be granted by the user. Both the user and the system can revoke the SCHEDULE_EXACT_ALARM permission.

To check whether the permission is granted to your app, call canScheduleExactAlarms() before trying to set an exact alarm. When the SCHEDULE_EXACT_ALARM permission is revoked for your app, your app stops, and all future exact alarms are canceled. This also means that the value returned by canScheduleExactAlarms() stays valid for the entire lifecycle of your app.

When the SCHEDULE_EXACT_ALARMS permission is granted to your app, the system sends it the ACTION_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED broadcast. Your app should implement a broadcast receiver that does the following:

  1. Confirms that your app still has the special app access. To do so, call canScheduleExactAlarms() . This check protects your app from the case where the user grants your app the permission, then revokes it almost immediately afterward.
  2. Reschedules any exact alarms that your app needs, based on its current state. This logic should be similar to what your app does when it receives the ACTION_BOOT_COMPLETED broadcast.

Ask users to grant the SCHEDULE_EXACT_ALARM permission

The option is called 'Allow setting alarms and reminders'
Figure 1. "Alarms & reminders" special app access page in system settings, where users can allow your app to set exact alarms.

If necessary, you can send users to the Alarms & reminders screen in system settings, as shown in Figure 1. To do so, complete the following steps:

  1. In your app's UI, explain to the user why your app needs to schedule exact alarms.
  2. Invoke an intent that includes the ACTION_REQUEST_SCHEDULE_EXACT_ALARM intent action.

Set a repeating alarm

Repeating alarms allow the system to notify your app on a recurring schedule.

A poorly-designed alarm can cause battery drain and put a significant load on servers. For this reason, on Android 4.4 (API level 19) and higher, all repeating alarms are inexact alarms .

A repeating alarm has the following characteristics:

  • An alarm type. For more discussion, see Choose an alarm type .

  • A trigger time. If the trigger time you specify is in the past, the alarm triggers immediately.

  • The alarm's interval. For example, once a day, every hour, or every 5 minutes.

  • A pending intent that fires when the alarm is triggered. When you set a second alarm that uses the same pending intent, it replaces the original alarm.

To cancel a PendingIntent() , pass FLAG_NO_CREATE to PendingIntent.getService() to get an instance of the intent (if it exists), then pass that intent to 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);
}

Choose an alarm type

One of the first considerations in using a repeating alarm is what its type should be.

There are two general clock types for alarms: "elapsed real time" and "real time clock" (RTC). Elapsed real time uses the "time since system boot" as a reference, and real time clock uses UTC (wall clock) time. This means that elapsed real time is suited to setting an alarm based on the passage of time (for example, an alarm that fires every 30 seconds) since it isn't affected by time zone or locale. The real time clock type is better suited for alarms that are dependent on current locale.

Both types have a "wakeup" version, which says to wake up the device's CPU if the screen is off. This ensures that the alarm will fire at the scheduled time. This is useful if your app has a time dependency. For example, if it has a limited window to perform a particular operation. If you don't use the wakeup version of your alarm type, then all the repeating alarms will fire when your device is next awake.

If you simply need your alarm to fire at a particular interval (for example, every half hour), use one of the elapsed real time types. In general, this is the better choice.

If you need your alarm to fire at a particular time of day, then choose one of the clock-based real time clock types. Note, however, that this approach can have some drawbacks. The app may not translate well to other locales, and if the user changes the device's time setting, it could cause unexpected behavior in your app. Using a real time clock alarm type also does not scale well, as discussed above. We recommend that you use an "elapsed real time" alarm if you can.

Here is the list of types:

  • ELAPSED_REALTIME : Fires the pending intent based on the amount of time since the device was booted, but doesn't wake up the device. The elapsed time includes any time during which the device was asleep.

  • ELAPSED_REALTIME_WAKEUP : Wakes up the device and fires the pending intent after the specified length of time has elapsed since device boot.

  • RTC : Fires the pending intent at the specified time but does not wake up the device.

  • RTC_WAKEUP : Wakes up the device to fire the pending intent at the specified time.

Examples of elapsed real time alarms

Here are some examples of using ELAPSED_REALTIME_WAKEUP

Wake up the device to fire the alarm in 30 minutes, and every 30 minutes after that:

کاتلین

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

Wake up the device to fire a one-time (non-repeating) alarm in one minute:

کاتلین

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

Examples of real time clock alarms

Here are some examples of using RTC_WAKEUP .

Wake up the device to fire the alarm at approximately 2:00 pm, and repeat once a day at the same time:

کاتلین

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

Wake up the device to fire the alarm at precisely 8:30 am, and every 20 minutes thereafter:

کاتلین

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

Decide how precise your alarm needs to be

As previously described, choosing the alarm type is often the first step in creating an alarm. A further distinction is how precise you need your alarm to be. For most apps, setInexactRepeating() is the right choice. When you use this method, Android synchronizes multiple inexact repeating alarms and fires them at the same time. This reduces the drain on the battery.

Avoid using exact alarms if possible. However, for the rare app that has rigid time requirements, you can set an exact alarm by calling setRepeating() .

With setInexactRepeating() , you can't specify a custom interval the way you can with setRepeating() . You have to use one of the interval constants, such as INTERVAL_FIFTEEN_MINUTES , INTERVAL_DAY , and so on. See AlarmManager for the complete list.

Cancel an alarm

Depending on your app, you may want to include the ability to cancel the alarm. To cancel an alarm, call cancel() on the Alarm Manager, passing in the PendingIntent you no longer want to fire. به عنوان مثال:

کاتلین

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

Start an alarm when the device restarts

By default, all alarms are canceled when a device shuts down. To prevent this from happening, you can design your application to automatically restart a repeating alarm if the user reboots the device. This ensures that the AlarmManager will continue doing its task without the user needing to manually restart the alarm.

در اینجا مراحل انجام می شود:

  1. Set the RECEIVE_BOOT_COMPLETED permission in your application's manifest. This allows your app to receive the ACTION_BOOT_COMPLETED that is broadcast after the system finishes booting (this only works if the app has already been launched by the user at least once):

    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
  2. Implement a BroadcastReceiver to receive the broadcast:

    کاتلین

    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. Add the receiver to your app's manifest file with an intent filter that filters on the ACTION_BOOT_COMPLETED action:

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

    Notice that in the manifest, the boot receiver is set to android:enabled="false" . This means that the receiver will not be called unless the application explicitly enables it. This prevents the boot receiver from being called unnecessarily. You can enable a receiver (for example, if the user sets an alarm) as follows:

    کاتلین

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

    Once you enable the receiver this way, it will stay enabled, even if the user reboots the device. In other words, programmatically enabling the receiver overrides the manifest setting, even across reboots. The receiver will stay enabled until your app disables it. You can disable a receiver (for example, if the user cancels an alarm) as follows:

    کاتلین

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

Invoke alarms while the device is in Doze mode

Devices that run Android 6.0 (API level 23) support Doze mode, which helps extend device battery life. Alarms don't fire when the device is in Doze mode Any scheduled alarms are deferred until the device exits Doze. If you need to complete work even when the device is idle, there are several options available:

  • Set an exact alarm .

  • Use the WorkManager API, which is built to perform background work. You can indicate that the system should expedite your work so that the work finishes as soon as possible. For more information, see Schedule tasks with WorkManager

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

Every choice you make in designing your repeating alarm can have consequences in how your app uses (or abuses) system resources. For example, imagine a popular app that syncs with a server. If the sync operation is based on clock time and every instance of the app syncs at 11:00 pm, the load on the server could result in high latency or even "denial of service." Follow these best practices in using alarms:

  • Add randomness (jitter) to any network requests that trigger as a result of a repeating alarm:

    • Do any local work when the alarm triggers. "Local work" means anything that doesn't hit a server or require the data from the server.

    • At the same time, schedule the alarm that contains the network requests to fire at some random period of time.

  • Keep your alarm frequency to a minimum.

  • Don't wake up the device unnecessarily (this behavior is determined by the alarm type, as described in Choose an alarm type ).

  • Don't make your alarm's trigger time any more precise than it has to be.

    Use setInexactRepeating() instead of setRepeating() . When you use setInexactRepeating() , Android synchronizes repeating alarms from multiple apps and fires them at the same time. This reduces the total number of times the system must wake the device, thus reducing drain on the battery. As of Android 4.4 (API Level 19), all repeating alarms are inexact alarm . Note that while setInexactRepeating() is an improvement over setRepeating() , it can still overwhelm a server if every instance of an app hits the server around the same time. Therefore, for network requests, add some randomness to your alarms, as discussed previously.

  • Avoid basing your alarm on clock time if possible.

    Repeating alarms that are based on a precise trigger time don't scale well. Use ELAPSED_REALTIME if you can. The different alarm types are described in more detail in the following section.