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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  • 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. เพิ่ม BroadcastReceiver ลงในไฟล์ 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" ซึ่งหมายความว่าระบบจะไม่เรียกใช้ BroadcastReceiver เว้นแต่แอปพลิเคชันจะเปิดใช้อย่างชัดแจ้ง ซึ่งจะป้องกันไม่ให้มีการเรียกใช้ Boot Receiver โดยไม่จำเป็น คุณสามารถเปิดใช้ BroadcastReceiver (เช่น หากผู้ใช้ตั้งปลุก) ได้ดังนี้

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

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

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

เรียกใช้การปลุกขณะที่อุปกรณ์อยู่ในโหมด Doze

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

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

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

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

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

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

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

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

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

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

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

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