ตั้งเวลาปลุก

การปลุก (อิงตามคลาส AlarmManager) ช่วยให้คุณดำเนินการตามเวลานอกอายุการใช้งานของแอปพลิเคชันได้ ตัวอย่างเช่น คุณอาจใช้การปลุกเพื่อเริ่มการดำเนินการที่ใช้เวลานาน เช่น การเริ่มบริการวันละครั้งเพื่อดาวน์โหลดพยากรณ์อากาศ

สัญญาณเตือนมีลักษณะดังนี้

  • ซึ่งช่วยให้คุณเรียกใช้ Intent ในเวลาและ/หรือช่วงเวลาที่กำหนด

  • คุณสามารถใช้ร่วมกับตัวรับการออกอากาศเพื่อกำหนดเวลางานหรือคำของานเพื่อดำเนินการอื่นๆ ได้

  • เหตุการณ์ทำงานนอกแอปพลิเคชัน คุณจึงใช้เหตุการณ์เพื่อทริกเกอร์เหตุการณ์หรือการดําเนินการได้แม้ว่าแอปจะไม่ทํางานอยู่และอุปกรณ์จะอยู่ในโหมดสลีปก็ตาม

  • ซึ่งจะช่วยคุณลดข้อกำหนดด้านทรัพยากรของแอป คุณสามารถกำหนดเวลาการดำเนินการโดยไม่ต้องใช้ตัวจับเวลาหรือบริการที่ทำงานอย่างต่อเนื่อง

ตั้งปลุกแบบไม่แน่นอน

เมื่อแอปตั้งการปลุกที่ไม่ถูกต้อง ระบบจะส่งการปลุกในช่วงเวลาหนึ่งในอนาคต การปลุกที่ไม่แน่นอนจะรับประกันบางอย่างเกี่ยวกับเวลาในการส่งการปลุก ขณะเดียวกันก็เคารพข้อจำกัดในการประหยัดแบตเตอรี่ เช่น โหมดสลีป

นักพัฒนาแอปสามารถใช้การรับประกัน API ต่อไปนี้เพื่อปรับแต่งเวลาในการส่งการแจ้งเตือนที่ไม่ถูกต้อง

ส่งการปลุกหลังเวลาที่กำหนด

หากแอปเรียกใช้ set(), setInexactRepeating() หรือ setAndAllowWhileIdle() ระบบจะไม่ปลุกก่อนเวลาทริกเกอร์ที่ระบุ

ใน Android 12 (API ระดับ 31) ขึ้นไป ระบบจะเรียกใช้การปลุกภายใน 1 ชั่วโมงนับจากเวลาที่ทริกเกอร์ที่ระบุ เว้นแต่จะมีการใช้ข้อจำกัดการประหยัดแบตเตอรี่ เช่น โหมดประหยัดแบตเตอรี่หรือโหมดสลีป

ส่งสัญญาณเตือนในกรอบเวลา

หากแอปเรียกใช้ setWindow() การปลุกจะไม่ดังขึ้นก่อนเวลาทริกเกอร์ที่ระบุ ระบบจะส่งเสียงปลุกภายในกรอบเวลาที่กำหนดโดยเริ่มตั้งแต่เวลาที่ทริกเกอร์ที่ระบุ เว้นแต่จะมีข้อจำกัดการประหยัดแบตเตอรี่

หากแอปกำหนดเป้าหมายเป็น Android 12 ขึ้นไป ระบบจะเลื่อนเวลาเรียกใช้การปลุกที่ไม่แน่นอ��ตามกรอบเวลาอย่างน้อย 10 นาที ด้วยเหตุนี้ ค่าพารามิเตอร์ windowLengthMillis ภายใต้ 600000 จึงถูกตัดเป็น 600000

ส่งการแจ้งเตือนแบบซ้ำในช่วงเวลาที่ค่อนข้างสม่ำเสมอ

หากแอปเรียกใช้ setInexactRepeating() ระบบจะเรียกใช้การแจ้งเตือนหลายรายการ ดังนี้

  1. การปลุกครั้งแรกจะดังขึ้นภายในกรอบเวลาที่กำหนด โดยเริ่มจากเวลาทริกเกอร์ที่ระบุ
  2. การปลุกที่ตามมามักจะส่งเสียงเตือนหลังจากผ่านกรอบเวลาที่ระบุไว้แล้ว ระยะเวลาระหว่างการเรียกใช้การปลุก 2 ครั้งติดต่อกันอาจแตกต่างกันไป

ตั้งปลุกในเวลาที่แน่���อน

ระบบจะเรียกใช้การปลุกที่แน่นอนในเวลาที่แน่นอนในอนาคต

แอปส่วนใหญ่สามารถกำหนดเวลางานและกิจกรรมโดยใช้การปลุกที่ไม่แน่นอนเพื่อดำเนินการตามกรณีการใช้งานทั่วไปหลายรายการ หากฟังก์ชันหลักของแอปขึ้นอยู่กับการปลุกที่มีเวลาแน่นอน เช่น สําหรับแอปนาฬิกาปลุกหรือแอปปฏิทิน คุณก็ใช้การปลุกในเวลาที่แน่นอนแทนได้

กรณีการใช้งานที่อาจไม่จําเป็นต้องใช้การปลุกในเวลาที่แน่นอน

รายการต่อไปนี้แสดงเวิร์กโฟลว์ทั่วไปที่อาจไม่กำหนดให้ใช้การตั้งปลุกในเวลาที่แน่นอน

การกำหนดเวลาการดำเนินการตามช่วงเวลาตลอดอายุของแอป
คลาส Handler มีวิธีที่ดีมากมายในการจัดการกับการดำเนินการจับเวลา เช่น การทำงานบางอย่างทุกๆ n วินาทีขณะที่แอปทำงานอยู่ มีดังนี้ postAtTime() และ postDelayed() โปรดทราบว่า API เหล่านี้ใช้เวลาทำงานของระบบ ไม่ใช่แบบเรียลไทม์
งานพื้นหลังที่กำหนดเวลาไว้ เช่น การอัปเดตแอปและการอัปโหลดบัน��ึก
WorkManager มีวิธีกำหนดเวลางานตามช่วงเวลาที่ต้องคำนึงถึงเวลา คุณสามารถระบุช่วงเวลาที่ทำงานซ้ำและ flexInterval (ขั้นต่ำ 15 นาที) เพื่อกำหนดรันไทม์แบบละเอียดสำหรับงาน
การดําเนินการที่ผู้ใช้ระบุซึ่งควรเกิดขึ้นหลังจากเวลาหนึ่งๆ (แม้ว่าระบบจะอยู่ในสถานะไม่มีการใช้งานก็ตาม)
ใช้การปลุกที่ไม่แน่นอน โปรดโทรหา setAndAllowWhileIdle()
การดําเนินการที่ผู้ใช้ระบุซึ่งควรเกิดขึ้นหลังจากเวลาหนึ่งๆ
ใช้การปลุกที่ไม่แน่นอน โปรดโทรหา set()
การดําเนินการที่ผู้ใช้ระบุซึ่งอาจเกิดขึ้นภายในกรอบเวลาที่ระบุ
ใช้การปลุกที่ไม่แน่นอน โปรดโทรหา setWindow() โปรดทราบว่าหากแอปกำหนดเป้าหมายเป็น Android 12 ขึ้นไป ระยะเวลาของกรอบเวลาต่ำสุดที่อนุญาตคือ 10 นาที

วิธีตั้งปลุกในเวลาที่แน่นอน

แอปสามารถตั้งปลุกในเวลาที่แน่นอนได้โดยใช้วิธีใดวิธีหนึ่งต่อไปนี้ วิธีการเหล่านี้จะเรียงลำดับให้รายการที่อยู่ใกล้ด้านล่างสุดแสดงรายการทำงานที่ใช้เวลามาก แต่ต้องใช้ทรัพยากรระบบมากกว่า

setExact()

เปิดการปลุกในเวลาที่เกือบจะแน่นอนในอนาคต ตราบใดที่มาตรการอื่นๆ ในการประหยัดแบตเตอรี่ไม่ได้มีผล

ใช้วิธีนี้เพื่อตั้งปลุกในเวลาที่แน่นอน เว้นแต่ว่างานของแอปจะมีความเกี่ยวข้องกับเวลาของผู้ใช้

setExactAndAllowWhileIdle()

เปิดการปลุกในเวลาที่เกือบจะแน่นอนในอนาคต แม้ว่าจะมีมาตรการประหยัดแบตเตอรี่อยู่ก็ตาม

setAlarmClock()

เรียกใช้การปลุกในเวลาที่แน่นอนในอนาคต เนื่องจากผู้ใช้จะเห็นการแจ้งเตือนเหล่านี้อย่างชัดเจน ระบบจึงไม่เคยปรับเวลานำส่ง ระบบจะระบุว่าการแจ้งเตือนเหล่านี้สำคัญที่สุดและจะไม่ออกจากโหมดพลังงานต่ำหากจำเป็นในการส่งการแจ้งเตือน

การใช้ทรัพยากรระบบ

เมื่อระบบทริกเกอร์การปลุกที่ตรงกับการตั้งค่าของแอป อุปกรณ์จะใช้ทรัพยากรจำนวนมาก เช่น อายุการใช้งานแบตเตอรี่ โดยเฉพาะอย่างยิ่งหากอยู่ในโหมดประหยัดพลังงาน นอกจากนี้ ระบบยังจัดกลุ่มคำขอเหล่านี้เพื่อใช้ทรัพยากรอย่างมีประสิทธิภาพมากขึ้นได้ยาก

เราขอแนะนําอย่างยิ่งให้คุณสร้างการแจ้งเตือนที่ไม่แน่นอนทุกครั้งที่เป็นไปได้ หากต้องการทํางานได้นานขึ้น ให้ตั้งเวลาโดยใช้ WorkManager หรือ JobScheduler จากการปลุก BroadcastReceiver หากต้องการทำงานขณะที่อุปกรณ์อยู่ในโหมดสลีป ให้สร้างการปลุกในเวลาที่ไม่แน่นอนโดยใช้ setAndAllowWhileIdle() แล้วเริ่มงานจากการปลุก

ประกาศสิทธิ์การปลุกในเวลาที่แน่นอนที่เหมาะสม

หากแอปกำหนดเป้าหมายเป็น Android 12 ขึ้นไป คุณต้องได้รับสิทธิ์เข้าถึงพิเศษของแอปสำหรับ "การปลุกและการช่วยเตือน" โดยประกาศสิทธิ์ SCHEDULE_EXACT_ALARM ในไฟล์ Manifest ของแอป ดังที่แสดงในข้อมูลโค้ดต่อไปนี้

<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

สิทธิ์ SCHEDULE_EXACT_ALARM ต้องได้รับอนุญาตจากผู้ใช้ ซึ่งแตกต่างจาก USE_EXACT_ALARM ทั้งผู้ใช้และระบบสามารถเพิกถอนสิทธิ์ SCHEDULE_EXACT_ALARM ได้

หากต้องการตรวจสอบว่ามีการให้สิทธิ์แก่แอปของคุณหรือไม่ ให้โทรหา canScheduleExactAlarms() ก่อนที่จะพยายามตั้งปลุกในเวลาที่แน่นอน เมื่อเพิกถอนสิทธิ์ SCHEDULE_EXACT_ALARM ของแอป แอปจะหยุดทำงานและการปลุกในเวลาที่แน่นอนทั้งหมดในอนาคตจะถูกยกเลิก ซึ่งหมายความว่าค่าที่ canScheduleExactAlarms() แสดงผลจะยังคงใช้งานได้ตลอดอายุของแอป

เมื่อแอปได้รับสิทธิ์ SCHEDULE_EXACT_ALARMS แล้ว ระบบจะส่งการออกอากาศ ACTION_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED ไปยังแอป แอปของคุณควรใช้ Broadcast Receiver ซึ่งทำสิ่งต่อไปนี้

  1. ยืนยันว่าแอปของคุณยังมีสิทธิ์เข้าถึงแอปพิเศษ โดยโทรไปที่ canScheduleExactAlarms() การตรวจสอบนี้ช่วยปกป้องแอปของคุณในกรณีที่ผู้ใช้ให้สิทธิ์แก่แอปของคุณ แล้วเพิกถอนสิทธิ์นั้นเกือบจะทันที
  2. กำหนดเวลาการปลุกในเวลาที่แน่นอนที่แอปของคุณต้องใช้ใหม่โดยอิงตามสถานะปัจจุบันของแอป ตรรกะนี้ควรคล้ายกับสิ่งที่แอปทำเมื่อได้รับการออกอากาศ ACTION_BOOT_COMPLETED

ขอให้ผู้ใช้ให้สิทธิ์ SCHEDULE_EXACT_ALARM

ตัวเลือกนี้เรียกว่า &quot;อนุญาตให้ตั้งปลุกและการช่วยเตือน&quot;
รูปที่ 1 หน้า "การปลุกและการช่วยเตือน" พิเศษของแอปในการเข้าถึง ในการตั้งค่าระบบ ซึ่งผู้ใช้อนุญาตให้แอปตั้งการปลุกในเวลาที่แน่นอนได้

หากจำเป็น คุณสามารถส่งผู้ใช้ไปยังหน้าจอการปลุกและการช่วยเตือนในการตั้งค่าระบบได้ ดังที่แสดงในรูปที่ 1 โดยทำตามขั้นตอนต่อไปนี้

  1. ใน UI ของแอป ให้อธิบายให้ผู้ใช้ทราบว่าเหตุใดแอปจึงต้องตั้งเวลาการปลุกให้ตรงเวลา
  2. เรียกใช้ Intent ที่มีการดำเนินการของ Intent ACTION_REQUEST_SCHEDULE_EXACT_ALARM

ตั้งปลุกซ้ำ

การปลุกซ้ำช่วยให้ระบบแจ้งเตือนแอปของคุณตามกำหนดการที่เกิดซ้ำได้

การปลุกที่ออกแบบมาไม่ดีอาจทำให้แบตเตอรี่หมดและทำให้เซิร์ฟเวอร์มีภาระงานมาก ด้วยเหตุนี้ ใน Android 4.4 (API ระดับ 19) ขึ้นไป การปลุกซ้ำทั้งหมดจึงเป็นการปลุกที่ไม่ถูกต้อง

การปลุกซ้ำมีลักษณะดังต่อไปนี้

  • ประเภทการปลุก ดูการพ��ดคุยเพิ่มเติมที่หัวข้อเลือกประเภทการปลุก

  • เวลาทริกเกอร์ หากเวลาทริกเกอร์ที่คุณระบุเป็นเวลาที่ผ่านมาแล้ว การปลุกจะทำงานทันที

  • ช่วงเวลาของการปลุก เช่น วันละครั้ง ทุกชั่วโมง หรือทุก 5 นาที

  • ความตั้งใจที่รอดำเนินการที่จะเริ่มทำงานเมื่อมีการเรียกให้ปลุก เมื่อคุณตั้งปลุกครั้งที่ 2 ที่ใช้ Intent ที่รอดำเนินการเดียวกัน ปลุกครั้งที่ 2 จะแทนที่การปลุกเดิม

หากต้องการยกเลิก PendingIntent() ให้ส่ง FLAG_NO_CREATE ไปยัง PendingIntent.getService() เพื่อรับอินสแตนซ์ของ Intent (หากมี) จากนั้นส่ง Intent นั้นไปยัง 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);
}

เลือกประเภทการปลุก

ข้อควรพิจารณาประการแรกในการใช้การปลุก��้ำคือประเภทการปลุก

นาฬิกาปลุกมี 2 ประเภท ได้แก่ "เวลาเรียลไทม์" และ "นาฬิกาเรียลไทม์" (RTC) เวลาจริงที่ผ่านไปจะใช้ "เวลา���ั�����ั้ง�����่����บบบูต" เป็นข้อมูลอ้างอิง และนาฬิกาแบบเรียลไทม์จะใช้เวลา UTC (นาฬิกาตั้งโต๊ะ) ซึ่งหมายความว่าเวลาจริงที่ผ่านไปเหมาะสำหรับการตั้งปลุกตามช่วงเวลา (เช่น ปลุกที่ทำงานทุก 30 วินาที) เนื่องจากไม่ได้รับผลกระทบจากเขตเวลาหรือภาษา นาฬิกาแบบเรียลไทม์เหมาะสําหรับการปลุกที่ขึ้นอยู่กับภาษาปัจจุบันมากกว่า

ทั้งสองประเภทจะมีเวอร์ชัน "Wakeup" ซึ่งใช้ชื่อว่าปลุก CPU ของอุปกรณ์หากหน้าจอปิดอยู่ วิธีนี้ช่วยให้แน่ใจว่าการปลุกจะเริ่มทำงานตามเวลาที่กำหนดไว้ วิธีนี้มีประโยชน์หากแอปของคุณมีเวลาเป็นปัจจัย เช่น หากมีกรอบเวลาจํากัดในการดําเนินการบางอย่าง หากคุณไม่ได้ใช้การปลุกประเภท "ปลุกให้ตื่น" การปลุกซ้ำทั้งหมดจะทำงานเมื่ออุปกรณ์ตื่นขึ้นมาครั้งถัดไป

หากต้องการเพียงแค่ให้การปลุกทำงานเป็นช่วงๆ (เช่น ทุกครึ่งชั่วโมง) ให้ใช้ประเภทเวลาจริงที่ผ่านไปอย่างใดอย่างหนึ่ง โดยทั่วไปแล้ว ตัวเลือกนี้เหมาะกว่า

หากต้องการให้นาฬิกาปลุกทำงานในเวลาที่เจาะจงของวัน ให้เลือกประเภทนาฬิกาแบบเรียลไทม์ตามนาฬิกา แต่โปรดทราบว่าวิธีนี้อาจมีข้อเสียบางประการ แอปอาจแปลเป็นภาษาท้องถิ่นอื่นๆ ได้ไม่สอดคล้องกัน และหากผู้ใช้เปลี่ยนการตั้งค่าเวลาของอุปกรณ์ ก็อาจทําให้แอปทำงานในลักษณะที่ไม่คาดคิดได้ นอกจากนี้ การใช้นาฬิกาปลุกแบบเรียลไทม์ก็ปรับขนาดได้ไม่ดีเช่นกัน ตามที่อธิบายไว้ข้างต้น เราขอแนะนำให้คุณใช้การปลุก "ที่ผ่านไปแบบเรียลไทม์" หากทำได้

ประเภทรายการมีดังนี้

  • ELAPSED_REALTIME: เริ่มการทำงานของ Intent ที่รอดำเนินการตามระยะเวลาตั้งแต่เปิดเครื่องอุปกรณ์ แต่ไม่ปลุกระบบอุปกรณ์ เวลาผ่านไปจะรวมเวลาที่อุปกรณ์อยู่ในโหมดสลีปด้วย

  • ELAPSED_REALTIME_WAKEUP:ตื่นขึ้นอุปกรณ์และเรียกใช้ Intent ที่รอดำเนินการหลังจากผ่านไปตามระยะเวลาที่ระบุนับตั้งแต่ที่อุปกรณ์บูต

  • RTC: เรียกใช้ Intent ที่รอดำเนินการตามเวลาที่ระบุ แต่ไม่ปลุกอุปกรณ์

  • RTC_WAKEUP: ปลุกอุปกรณ์เพื่อเรียกใช้ Intent ที่รอดําเนินการตามเวลาที่ระบุ

ตัวอย่างการปลุกแบบเรียลไทม์ที่ผ่านไปแล้ว

ตัวอย่างการใช้ 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);

วิธีปลุกอุปกรณ์ให้ปลุก 1 ครั้ง (แบบไม่ซ้ำ) ใน 1 นาที

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

ปลุกระบบอุปกรณ์ให้เริ่มทำงานในเวลาประมาณ 14: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 ในไฟล์ Manifest ของแอปพลิเคชัน ซึ่งจะช่วยให้แอปของคุณได้รับ ACTION_BOOT_COMPLETED ที่ระบบประกาศหลังจากบูตเสร็จ (การดำเนินการนี้จะได้ผลก็ต่อเมื่อผู้ใช้เปิดแอปอย่างน้อย 1 ครั้งแล้วเท่านั้น)

    <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. เพิ่มตัวรับสัญญาณลงในไฟล์ Manifest ของแอปด้วยตัวกรอง 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>

    โปรดทราบว่าในไฟล์ Manifest มีการตั้งค่าตัวรับการบูตเป็น 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);

    เมื่อเปิดใช้รีซีฟเวอร์ด้วยวิธีนี้ รีซีฟเวอร์จะเปิดใช้อยู่แม้ว่าผู้ใช้จะรีบูตอุปกรณ์ก็ตาม กล่าวคือ การเปิดใช้ตัวรับแบบเป็นโปรแกรมจะลบล้างการตั้งค่าไฟล์ Manifest แม้ในการรีบูต ตัวรับจะเปิดอยู่จนกว่าแอปจะปิดใช้ คุณปิดใช้รีซีฟเวอร์ได้ (เช่น หากผู้ใช้ยกเลิกการปลุก) โดยทำดังนี้

    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 (API ระดับ 23) รองรับโหมดDoze ซึ่งช่วยยืดอายุการใช้งานแบตเตอรี่ของอุปกรณ์ การปลุกจะไม่ทำงานเมื่ออุปกรณ์อยู่ในโหมดสลีป ระบบจะเลื่อนการปลุกที่ตั้งเวลาไว้จนกว่าอุปกรณ์จะออกจากโหมดสลีป หากต้อ��การทำงานให้เสร็จสมบูรณ์แม้ในขณะที่อุปกรณ์ไม่ได้ใช้งาน คุณมีตัวเลือกหลายอย่างดังนี้

แนวทางปฏิบัติแนะนำ

ตัวเลือกที่คุณเลือกในการออกแบบการปลุกซ้ำอาจมีผลต่อวิธีที่แอปใช้ (หรือละเมิด) ทรัพยากรระบบ ตัวอย่างเช่น สมมติว่าแอปยอดนิยมที่ซิงค์กับเซิร์ฟเวอร์ หากการดำเนินการซิงค์อิงตามเวลาของนาฬิกาและอินสแตนซ์ทั้งหมดของแอปซิงค์กันในเวลา 23:00 น. ภาระงานในเซิร์ฟเวอร์อาจส่งผลให้เกิดความล่าช้าสูงหรือแม้แต่ "การปฏิเสธการให้บริการ" ทำตามแนวทางปฏิบัติแนะนำต่อไปนี้ในการใช้การปลุก

  • เพิ่มการสุ่ม (Jitter) ให้กับคำขอเครือข่ายที่ทริกเกอร์ขึ้นเนื่องจากการปลุกซ้ำ

    • ทำงานเฉพาะที่เมื่อมีสัญญาณเตือน "การทํางานในเครื่อง" หมายถึงการดำเนินการใดๆ ที่ไม่ได้เข้าถึงเซิร์ฟเวอร์หรือต้องใช้ข้อมูลจากเซิร์ฟเวอร์

    • ในขณะเดียวกัน ให้ตั้งเวลาการปลุกที่มีคำขอเครือข่ายให้ทำงานเป็นช่วงๆ แบบสุ่ม

  • ตั้งความถี่การปลุกให้น้อยที่สุด

  • อย่าปลุกระบบอุปกรณ์โดยไม่จำเป็น (การทำงานนี้จะกำหนดโดยประเภทการปลุก ตามที่อธิบายไว้ในเลือกประเภทการปลุก)

  • อย่าตั้งค่าเวลาทริกเกอร์ของนาฬิกาปลุกให้แม่นยำเกินความจำเป็น

    ใช้ setInexactRepeating() instead of setRepeating() เมื่อคุณใช้ setInexactRepeating() ระบบ Android จะซิงค์การปลุกซ้ำจากหลายแอปและเปิดการปลุกพร้อมกัน ซึ่งจะช��วยลดจำนวนครั้งที่ระบบต้องปลุกอุปกรณ์ จึงช่วยประหยัดแบตเตอรี่ ตั้งแต่ Android 4.4 (API ระดับ 19) การปลุกซ้ำทั้งหมดจะเป็นการปลุกที่ไม่แน่นอน โปรดทราบว่าแม้ว่า setInexactRepeating() จะมีประสิทธิภาพดีกว่า setRepeating() แต่ก็ยังอาจทำให้เซิร์ฟเวอร์ทำงานหนักเกินไปได้หากอินสแตนซ์ทั้งหมดของแอปเข้าถึงเซิร์ฟเวอร์ในเวลาใกล้เคียงกัน ดังนั้น สําหรับคําขอเครือข่าย ให้เพิ่มความสุ่มให้กับการแจ้งเตือนดังที่ได้กล่าวไว้ก่อนหน้านี้

  • หลีกเลี่ยงการตั้งปลุกตามเวลาของนาฬิกา หากเป็นไปได้

    การปลุกซ้ำที่อิงตามเวลาทริกเกอร์ที่แน่นอนจะปรับขนาดได้ไม่ดี ใช้ ELAPSED_REALTIME หากทำได้ ประเภทต่างๆ ของการปลุกจะอธิบายไว้อย่างละเอียดในส่วนต่อไปนี้