جدولة المنبّهات

المنبّهات (استنادًا إلى AlarmManager الفصل) طريقة لإجراء العمليات المستندة إلى الوقت خارج الفترة منذ إنشاء التطبيق. على سبيل المثال، يمكنك استخدام تنبيه لبدء عملية طويلة الأمد، مثل كبدء خدمة مرة واحدة في اليوم لتنزيل توقعات الطقس.

تشمل المنبّهات السمات التالية:

  • تتيح لك هذه الميزة تشغيل "المقصودات" في أوقات و/أو فواصل زمنية محدّدة.

  • ويمكنك استخدامها مع أجهزة استقبال البث لتحديد مواعيد المهام أو WorkRequests لتنفيذ عمليات أخرى.

  • تعمل هذه الخدمات خارج نطاق تطبيقك، لذا يمكنك استخدامها لبدء الأحداث أو الإجراءات حتى في حال عدم تشغيل تطبيقك، وحتى إذا كان الجهاز في وضع السكون.

  • وتساعدك في تقليل متطلبات الموارد لتطبيقك. يمكنك جدولة العمليات بدون الاعتماد على الموقّتات أو الخدمات التي تعمل باستمرار.

ضبط منبّه غير دقيق

عندما يضبط أحد التطبيقات منبّهًا غير محدَّد، يُرسِل النظام الإنذار في مرحلة ما. في المستقبل. توفر المنبهات غير المحددة بعض الضمانات فيما يتعلق بتوقيت تسليم المنبّه مع مراعاة قيود توفير شحن البطارية، مثل قيلولة:

يمكن للمطوّرين الاستفادة من ضمانات واجهة برمجة التطبيقات التالية لتخصيص توقيت إرسال التنبيهات غير الدقيقة.

ضبط منبّه بعد وقت محدّد

إذا كان تطبيقك يطلب البيانات من set()، setInexactRepeating()، أو setAndAllowWhileIdle()، لا ينطلق صوت الإنذار أبدًا قبل وقت التشغيل المحدد.

في نظام التشغيل Android 12 (المستوى 31 من واجهة برمجة التطبيقات) والإصدارات الأحدث، يشغِّل النظام المنبّه في مهلة تبلغ ساعة واحدة من وقت التفعيل المقدَّم، ما لم تكن أي قيود لتوفير طاقة البطارية مفعَّلة، مثل ميزة توفير شحن البطارية أو وضع "الاستراحة".

ضبط منبّه خلال فترة زمنية

إذا اتصل تطبيقك بـ setWindow()، لن يرنّ المنبّه قبل أن يتم تزويد التطبيق. وقت الإطلاق. ما لم يتم تطبيق أي قيود على توفير شحن البطارية، سيتم ضبط المنبّه على تسليمه خلال الفترة الزمنية المحدّدة، بدءًا من المشغّل المحدّد الوقت.

إذا كان تطبيقك يستهدف الإصدار 12 من نظام التشغيل Android أو إصدارًا أحدث، قد يؤخر النظام استدعاء إنذار غير محدد ضمن إطار زمني لمدة 10 دقائق على الأقل. بالنسبة ولهذا السبب، يتم اقتصاص قيم معلَمات windowLengthMillis ضمن 600000 إلى 600000

إطلاق منبّه متكرّر على فترات منتظمة تقريبًا

إذا كان تطبيقك يطلب البيانات من setInexactRepeating()، يستدعي النظام تنبيهات متعددة:

  1. ينطلق المنبّه الأول خلال الفترة الزمنية المحدّدة، بدءًا من وقت التفعيل المحدّد.
  2. يتم عادةً تفعيل المنبّهات اللاحقة بعد انقضاء الفترة الزمنية المحدّدة. يمكن أن يختلف الوقت بين استدعاءين متتاليين للإنذار.

ضبط منبّه محدّد الوقت

يُشغِّل النظام منبّهًا دقيقًا في لحظة محدّدة في المستقبل.

يمكن لمعظم التطبيقات جدولة المهام والأحداث باستخدام منبّهات غير محدَّدة وإكمال العديد من حالات الاستخدام الشائعة. إذا كانت الوظيفة الأساسية لتطبيقك تعتمد على منبّه محدَّد الوقت بدقة، مثل تطبيق ساعة منبّه أو تطبيق تقويم، فلا بأس باستخدام منبّه محدَّد الوقت بدلاً من ذلك.

حالات الاستخدام التي قد لا تتطلّب ضبط منبّهات محدَّدة الوقت

تعرض القائمة التالية عمليات سير العمل الشائعة التي قد لا تتطلب منبّهًا محددًا:

جدولة عمليات تحديد التوقيت أثناء مدة استخدام تطبيقك
تتضمّن فئة Handler عدة methods جيدة لمعالجة العمليات المتعلقة بالتوقيت، مثل تنفيذ بعض الأعمال كل n ثانية عندما يكون تطبيقك قيد التشغيل: postAtTime() و postDelayed(). تجدر الإشارة إلى أنّ واجهات برمجة التطبيقات هذه تعتمد على مدة تشغيل النظام وليس في الوقت الفعلي.
الأعمال التي تم إجراؤها في الخلفية، مثل تحديث التطبيق وتحميل السجلّات
توفّر WorkManager طريقة لجدولة مواعيد دورية تتضمّن التوقيت. العمل. يمكنك توفير فاصل زمني متكرر وflexInterval (15 دقيقة كحد أدنى) وتحدّد وقت تشغيل دقيق للعمل.
إجراء يحدده المستخدم يجب أن يحدث بعد وقت محدد (حتى إذا كان النظام في حالة عدم النشاط)
يُرجى استخدام منبّه غير محدَّد. يُرجى الاتصال بالرقم التالي: setAndAllowWhileIdle().
إجراء يحدّده المستخدم من المفترض أن يحدث بعد وقت محدّد
يُرجى استخدام منبّه غير محدَّد. على وجه التحديد، اتصل set()
إجراء يحدّده المستخدم ويمكن أن يحدث خلال فترة زمنية محدّدة
استخدام منبّه غير دقيق على وجه التحديد، اتصل setWindow() يُرجى ملاحظة أنّه إذا كان تطبيقك يستهدف الإصدار 12 من نظام التشغيل Android أو إصدارًا أحدث، فإن أصغر المدة المسموح بها هي 10 دقائق.

طرق ضبط منبّه محدّد الوقت

يمكن لتطبيقك ضبط منبّهات محدَّدة الوقت باستخدام إحدى الطرق التالية. هذه الطرق مرتّبة بحيث تكون النتائج الأقرب إلى أسفل القائمة أكثر ذات أهمية كبيرة للوقت ولكنها تتطلب المزيد من موارد النظام.

setExact()

تشغيل منبّه في وقت دقيق تقريبًا في المستقبل، ما دامت تدابير توفير البطارية الأخرى غير مفعّلة

يمكنك استخدام هذه الطريقة لضبط منبّهات محدَّدة الوقت، إلا إذا كان تطبيقك يعمل بالغ الأهمية للمستخدم.

setExactAndAllowWhileIdle()

تشغيل إنذار في وقت دقيق تقريبًا في المستقبل، حتى في حال توفير شحن البطارية التدابير.

setAlarmClock()

تشغيل إنذار في وقت محدد في المستقبل ولأنّ هذه التنبيهات مرئية للمستخدمين بشكل كبير، لا يعدّل النظام وقت إرسالها مطلقًا. يحدِّد النظام هذه المنبّهات على أنّها الأكثر أهمية ويترك الأوضاع المنخفضة الطاقة إذا لزم الأمر لعرض المنبّهات.

استهلاك موارد النظام

عندما يشغِّل النظام المنبّهات الدقيقة التي يضبطها تطبيقك، يستهلك الجهاز موارد كبيرة، مثل عمر البطارية، خاصةً إذا كان في وضع توفير الطاقة. بالإضافة إلى ذلك، لا يمكن للنظام تجميع هذه الطلبات بسهولة من أجل استخدام الموارد بكفاءة أكبر.

ننصحك بشدة بإنشاء إنذار غير دقيق كلما أمكن. لأداء عمل أطول، قم بجدولته باستخدام WorkManager أو JobScheduler من وقت المنبّه BroadcastReceiver لتنفيذ عمل معيّن أثناء وضع الجهاز في وضع "الاستراحة الذكية"، يمكنك إنشاء منبّه غير محدَّد الوقت باستخدام setAndAllowWhileIdle()، وبدء مهمة من المنبّه.

يُرجى تحديد الإذن المناسب للمنبّهات المحدَّدة الوقت

إذا كان تطبيقك يستهدف الإصدار 12 من نظام التشغيل Android أو الإصدارات الأحدث، يجب الحصول على إذن الوصول الخاص للتطبيق "المنبّهات والتذكيرات". ولإجراء ذلك، عليك الإفصاح عن SCHEDULE_EXACT_ALARM إذن في ملف بيان تطبيقك، كما هو موضّح في مقتطف الرمز التالي:

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

إذا كان تطبيقك يستهدف الإصدار 13 من نظام التشغيل Android (المستوى 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 مسبقًا لعمليات التثبيت الجديدة ل التطبيقات التي تستهدف الإصدار 13 من نظام التشغيل Android (المستوى 33 لواجهة برمجة التطبيقات) والإصدارات الأحدث. إذا نقل مستخدم بيانات التطبيق إلى جهاز يعمل بنظام التشغيل Android 14 من خلال عملية الاحتفاظ بنسخة احتياطية واستعادتها، سيتم رفض إذن SCHEDULE_EXACT_ALARM على الجهاز الجديد. ومع ذلك، إذا أحد التطبيقات الحالية لديه هذا الإذن بالفعل، فسيتم منحه مسبقًا عند ترقيات الجهاز إلى الإصدار 14 من نظام التشغيل Android.

ملاحظة: إذا تم ضبط المنبه المحدد باستخدام OnAlarmListener كما هو الحال مع السمة 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 من المستخدمين

يُعرَف هذا الخيار باسم &quot;السماح بضبط المنبّهات والتذكيرات&quot;.
الشكل 1. صفحة "أذونات خاصة للتطبيقات" في إعدادات النظام الخاصة بـ "المنبّهات والتذكيرات"، حيث يمكن للمستخدمين السماح لتطبيقك بضبط المنبّهات بدقة

إذا لزم الأمر، يمكنك توجيه المستخدمين إلى المنبّهات التذكيرات في النظام الإعدادات، كما هو موضح في الشكل 1. لإجراء ذلك، يُرجى إكمال الخطوات التالية:

  1. في واجهة المستخدم الخاصة بتطبيقك، اشرح للمستخدم سبب حاجة تطبيقك إلى وضع جدول زمني دقيق المنبّهات.
  2. استدعاء نية تتضمّن إجراء النيّة ACTION_REQUEST_SCHEDULE_EXACT_ALARM

ضبط منبّه متكرّر

تتيح التنبيهات المتكرّرة للنظام إرسال إشعارات إلى تطبيقك وفقًا لجدول زمني متكرّر.

يمكن أن يؤدي استخدام منبّه غير مصمَّم بشكل سيئ إلى استنزاف البطارية وزيادة الحمل على الخوادم. ولهذا السبب، على نظام التشغيل Android 4.4 (المستوى 19 من واجهة برمجة التطبيقات) والإصدارات الأحدث، المنبّهات المتكرّرة هي منبّهات غير محدَّدة الوقت.

يتسم المنبّه المتكرّر بالسمات التالية:

  • نوع المنبّه لمزيد من المناقشة، يُرجى الاطّلاع على اختيار نوع التنبيه.

  • وقت تشغيل. إذا كان وقت التشغيل الذي حددته في الماضي، فإن المنبه البيانات على الفور.

  • الفاصل الزمني للمنبّه على سبيل المثال، مرة واحدة في اليوم أو كل ساعة أو كل 5 دقائق.

  • هدف معلّق يتم تنشيطه عند تشغيل الإنذار. عند ضبط 🔔إنذار ثانٍ يستخدم النية المعلّقة نفسها، سيحلّ محل الإنذار الأصلي.

لإلغاء تذكرة PendingIntent()، عليك اجتياز الاختبار. FLAG_NO_CREATE إلى PendingIntent.getService() للحصول على مثيل للقصد (إن وجد)، AlarmManager.cancel()

Kotlin

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

Java

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 ثانية) نظرًا لأنه لا يتأثر المنطقة الزمنية أو اللغة. يكون نوع ساعة الوقت الفعلي أكثر ملاءمةً للإنذارات التي تعتمد على اللغة والمنطقة الحالية.

يتضمّن كلا النوعَين إصدارًا "للتنشيط"، والذي يُطلب من خلاله تنشيط وحدة المعالجة المركزية (CPU) في الجهاز إذا كانت الشاشة مطفأة. ويضمن ذلك تشغيل المنبّه في الوقت المحدّد. يكون ذلك مفيدًا إذا كان تطبيقك يعتمد على الوقت. على سبيل المثال، إذا كان لديه فترة محدودة لتنفيذ عملية معيّنة. إذا لم تكن تستخدِم إصدار المنبّه المخصّص للاستيقاظ، سيتم تشغيل كل المنبّهات المتكرّرة عندما يستيقظ جهازك في المرة التالية.

إذا كنت ببساطة بحاجة إلى تشغيل المنبّه بعد فاصل زمني معيّن (مثلاً، كل نصف ساعة)، استخدِم أحد أنواع الوقت الفعلي المنقضي. بشكل عام، هو الخيار الأفضل.

إذا أردت تشغيل المنبّه في وقت معيّن من اليوم، اختَر أحد الأوقات. أنواع الساعات المستندة إلى الساعة في الوقت الفعلي. يُرجى العلم أنّ هذا النهج يمكن أن يؤدي إلى بعض السلبيات. قد لا تتم ترجمة التطبيق بشكل جيد إلى اللغات الأخرى، وإذا تغيير المستخدم لإعداد الوقت في الجهاز، قد يؤدي ذلك إلى سلوك غير متوقّع في تطبيقك. لا يؤدي استخدام نوع منبه في الوقت الفعلي أيضًا إلى ضبط المقياس بشكل جيد، التي تمت مناقشتها أعلاه. ننصحك باستخدام إنذار "الوقت المنقضي بالثواني" إذا أمكن.

في ما يلي قائمة الأنواع:

  • ELAPSED_REALTIME: يتم تشغيل النية المعلّقة استنادًا إلى المدة التي انقضت منذ التمهيد للجهاز، ولكن لا يتم تنشيط الجهاز. تشير رسالة الأشكال البيانية ويشمل الوقت المنقضي أي وقت كان الجهاز في وضع السكون خلاله.

  • ELAPSED_REALTIME_WAKEUP: يوقظ الجهاز ويشغّل النية المعلّقة بعد انقضاء المدة الزمنية المحدّدة منذ تشغيل الجهاز.

  • RTC: لتشغيل رسالة intent التي كانت في انتظار المراجعة في الوقت المحدّد، ولكن لا يتم تنشيط الجهاز.

  • RTC_WAKEUP: استيقاظ الجهاز لتنشيط هدف الطلب المعلق في الوقت المحدّد.

أمثلة على المنبّهات التي تم تجاوزها في الوقت الفعلي

في ما يلي بعض الأمثلة على استخدام ELAPSED_REALTIME_WAKEUP

شغِّل الجهاز لتفعيل المنبّه بعد 30 دقيقة، وكل 30 دقيقة بعد ذلك:

Kotlin

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

Java

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

شغِّل الجهاز لتشغيل منبّه لمرة واحدة (غير متكرّر) بعد دقيقة واحدة:

Kotlin

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
)

Java

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 بعد الظهر تقريبًا التكرار مرة واحدة في اليوم في نفس الوقت:

Kotlin

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

Java

// 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 دقيقة بعد ذلك:

Kotlin

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
)

Java

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() في Alarm Manager، مع إدخال PendingIntent الذي لم تعُد تريد إطلاقه. مثلاً:

Kotlin

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

Java

// 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 لتلقي البث:

    Kotlin

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

    Java

    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". وهذا يعني أنّه لن يتم استدعاء المُستلِم ما لم يفعّله التطبيق صراحةً. ويمنع ذلك من استدعاء مستلِم التمهيد بدون داعٍ. يمكنك تفعيل جهاز استقبال (على سبيل المثال، إذا ضبط المستخدم تنبيهًا) على النحو التالي:

    Kotlin

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

    Java

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

    عند تفعيل جهاز الاستقبال بهذه الطريقة، سيبقى مفعّلاً، حتى إذا كان المستخدم إعادة تشغيل الجهاز. بعبارة أخرى، يؤدي تفعيل المُستلِمبرمجيًا إلى إلغاء إعداد البيان، حتى بعد عمليات إعادة التشغيل. سيظل جهاز الاستقبال مفعّلاً إلى أن يوقفه تطبيقك. يمكنك إيقاف جهاز استقبال (على سبيل المثال، إذا ألغى المستخدم أحد المنبّهات) على النحو التالي:

    Kotlin

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

    Java

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

تفعيل المنبّهات عندما يكون الجهاز في وضع "الاستراحة"

الأجهزة التي تعمل بنظام التشغيل Android 6.0 (المستوى 23 من واجهة برمجة التطبيقات) قيلولة الذي للمساعدة في إطالة عمر بطارية الجهاز. لا يتم إطلاق التنبيهات عندما يكون الجهاز قيد التشغيل. وضع القيلولة سيتم تأجيل أي منبّهات مُجدوَلة إلى أن يخرج الجهاز من وضع "القيلولة". إذا كنت بحاجة إلى إكمال العمل حتى عندما يكون الجهاز في وضع السكون، تتوفّر عدة خيارات :

  • اضبط منبّهًا دقيقًا.

  • استخدِم واجهة برمجة التطبيقات WorkManager API، وهي مصمّمة لتنفيذ المهام في الخلفية. يمكنك الإشارة إلى أنّه يجب على النظام تسريع عملك حتى تتمكّن من إكماله في أقرب وقت ممكن. لمزيد من المعلومات، يُرجى الاطّلاع على مقالة جدولة المهام باستخدام WorkManager.

أفضل الممارسات

يمكن أن يكون لكل خيار تحدّده في تصميم المنبّه المتكرّر عواقب في كيفية استخدام تطبيقك لموارد النظام (أو إساءة استخدامه لها). على سبيل المثال، تخيل أن تطبيق مشهور يتزامن مع الخادم. إذا كانت عملية المزامنة تستند إلى وقت المحاولة وكانت تتم مزامنة كل نسخة من التطبيق في الساعة 11:00 مساءً، قد يؤدي الحمل على الخادم إلى وقت استجابة طويل أو حتى "رفض الخدمة". يُرجى اتّباع أفضل الممارسات التالية عند استخدام المنبّهات:

  • أضف العشوائية (عدم الاستقرار) إلى أي طلبات شبكة يشغّل نتيجة لإنذار متكرر:

    • القيام بأي عمل محلي عند تشغيل المنبه "العمل على الجهاز فقط" يعني أي إجراء لا يتطلّب الاتصال بخادم أو طلب البيانات من الخادم.

    • وفي الوقت نفسه، يمكنك جدولة المنبه الذي يحتوي على طلبات الشبكة تطلق في فترة زمنية عشوائية.

  • حافظ على الحد الأدنى لمعدل تكرار المنبه.

  • عدم تنشيط الجهاز بدون داعٍ (يتم تحديد هذا السلوك من خلال نوع التنبيه، كما هو موضّح في اختيار نوع التنبيه)

  • لا تجعل وقت تشغيل المنبه أكثر دقة مما ينبغي.

    استخدِم setInexactRepeating() بدلاً من setRepeating(). عند استخدام setInexactRepeating()، يعمل Android على مزامنة المنبّهات المتكرّرة من تطبيقات متعددة وحالات الحرائق. معهما في نفس الوقت. ويؤدي ذلك إلى تقليل إجمالي عدد المرات التي يجب أن يوقظ فيها النظام الجهاز، وبالتالي تقليل استهلاك البطارية. اعتبارًا من الإصدار Android 4.4 (مستوى واجهة برمجة التطبيقات 19)، جميع المنبّهات المتكرّرة هي منبّه غير دقيق. يُرجى العِلم أنّه على الرغم من أنّ setInexactRepeating() يمثّل تحسُّنًا مقارنةً بsetRepeating()، يمكن أن يظلّ مثيل التطبيق يُحمّل الخادم في الوقت نفسه تقريبًا. لذلك، بالنسبة إلى طلبات الشبكة، أضِف بعض العشوائية إلى إنذاراتك، كما سبق أن ناقشنا.

  • تجنَّب ضبط المنبّه على وقت الساعة إن أمكن.

    لا يتم ضبط المنبهات المتكررة التي تستند إلى وقت تشغيل دقيق بشكل جيد. استخدام ELAPSED_REALTIME إذا يمكنك. يتم وصف أنواع التنبيهات المختلفة بمزيد من التفصيل في القسم التالي.