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

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

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

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

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

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

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

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

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

นักพัฒนาแอปสามารถใช้ประโยชน์จากการรับประกัน 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 ทั้งผู้ใช้และระบบสามารถเพิกถอนสิทธิ์ 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 ที่มี ACTION_REQUEST_SCHEDULE_EXACT_ALARM การดำเนินการของ Intent

ตั้งปลุกซ้ำ

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

การปลุกที่ออกแบบมาไม่ดีอาจทำให้แบตเตอรี่หมดและสร้างภาระงานอย่างหนักในเซิร์ฟเวอร์ ด้วยเหตุนี้ ใน 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 หาก ทำได้ เราจะอธิบายประเภทการปลุกต่างๆ โดยละเอียดในส่วนต่อไปนี้