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

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

การปลุกมีลักษณะดังนี้

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

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

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

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

ตั้งปลุกแบบไม่ตรงเวลา

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

นักพัฒนาแอปสามารถใช้ประโยชน์จากการรับประกัน 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 นาที

  • PendingIntent ที่เริ่มทำงานเมื่อมีการทริกเกอร์การปลุก เมื่อตั้งปลุกที่ 2 ซึ่งใช้ PendingIntent เดียวกัน ระบบจะแทนที่การปลุกเดิม

หากต้องการยกเลิก 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 วินาที) เนื่องจากไม่ได้รับผลกระทบจาก เขตเวลาหรือภาษา ประเภทนาฬิกาแบบเรียลไทม์เหมาะสำหรับนาฬิกาปลุกที่ ขึ้นอยู่กับภาษาปัจจุบันมากกว่า

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

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

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

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

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

  • ELAPSED_REALTIME_WAKEUP: ปลุกอุปกรณ์และเรียกใช้ PendingIntent หลังจากผ่านระยะเวลาที่ระบุ นับตั้งแต่การบูตอุปกรณ์

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

  • RTC_WAKEUP: ปลุก อุปกรณ์เพื่อเรียกใช้ PendingIntent ในเวลาที่ระบุ

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

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

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

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

  • ตั้งปลุกที่แน่นอน

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

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

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

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

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

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

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

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

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

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

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

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