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

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

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

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

  • คุณสามารถใช้ Chromecast ร่วมกับ Broadcast Receiver เพื่อกำหนดเวลา jobs หรือ WorkRequests เพื่อดำเนินการอื่นๆ การดำเนินงาน

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

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

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

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

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

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

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

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

ส่งการแจ้งเตือนในช่วงเวลาหนึ่ง

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

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

ตั้งปลุกซ้ำในช่วงเวลาที่สม่ำเสมอโดยประมาณ

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

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

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

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

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

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

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

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

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

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

setExact()

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

ใช้วิธีนี้เพื่อตั้งปลุกในเวลาที่แน่นอน เว้นแต่แอปจะทำงาน ในช่วงเวลาสำคัญสำหรับผู้ใช้

setExactAndAllowWhileIdle()

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

setAlarmClock()

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

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

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

เราขอแนะนําอย่างยิ่งให้คุณสร้างการแจ้งเตือนที่ไม่แน่นอนทุกครั้งที่เป็นไปได้ หากต้องการทำงานเป็นเวลานานขึ้น ให้กำหนดเวลาโดยใช้ WorkManager หรือ JobScheduler จาก BroadcastReceiver ของนาฬิกาปลุก ทำงานในขณะที่ อุปกรณ์อยู่ใน Doze สร้างการปลุกที่ไม่แน่นอนโดยใช้ 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 เช่น setExact API ไม่จําเป็นต้องใช้สิทธิ์ 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 ออกอากาศ แอปของคุณควรใช้การออกอากาศ รีซีฟเวอร์ที่ทำหน้าที่ ดังต่อไปนี้:

  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 นาที

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

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

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

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

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

  • 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 นาที

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 หากทำได้ การปลุกแบบอื่น ซึ่งอธิบายไว้ในรายละเอียดเพิ่มเติมในส่วนต่อไปนี้