AlarmManager
) ช่วยให้คุณดำเนินการตามเวลานอกอายุการใช้งานของแอปพลิเคชันได้
เช่น คุณอาจใช้การปลุกเพื่อเริ่มการดำเนินการที่ทำงานต่อเนื่องเป็นเวลานาน เช่น การเริ่มบริการวันละครั้งเพื่อดาวน์โหลดพยากรณ์อากาศ
สัญญาณเตือนมีลักษณะดังนี้
ซึ่งช่วยให้คุณเรียกใช้ Intent ในเวลาและ/หรือช่วงเวลาที่กำหนด
คุณสามารถใช้เซิร์ฟเวอร์ดังกล่าวร่วมกับ Broadcast Receiver เพื่อกำหนดเวลา jobs หรือ WorkRequests เพื่อดำเนินการอื่นๆ ได้
เหตุการณ์ทำงานนอกแอปพลิเคชัน คุณจึงใช้เหตุการณ์เพื่อทริกเกอร์เหตุการณ์หรือการดําเนินการได้แม้ว่าแอปจะไม่ทํางานอยู่และอุปกรณ์จะอยู่ในโหมดสลีปก็ตาม
ซึ่งจะช่วยคุณลดข้อกำหนดด้านทรัพยากรของแอป คุณสามารถกำหนดเวลาการดำเนินการโดยไม่ต้องใช้ตัวจับเวลาหรือบริการที่ทำงานอย่างต่อเนื่อง
ตั้งปลุกที่ไม่แน่นอน
เมื่อแอปตั้งการปลุกที่ไม่ถูกต้อง ระบบจะส่งการปลุกในช่วงเวลาหนึ่งในอนาคต การปลุกที่ไม่แน่นอนให้การรับประกันบางอย่างเกี่ยวกับเวลาในการส่งการปลุกโดยที่ยังคงเป็นไปตามข้อจำกัดในการประหยัดแบตเตอรี่ เช่น Doze
นักพัฒนาซอฟต์แวร์สามารถใช้ประโยชน์จากการรับประกัน API ต่อไปนี้เพื่อปรับแต่งเวลาของการส่งสัญญาณเตือนที่ไม่แน่นอน
ส่งการปลุกหลังจากเวลาที่กำหนด
หากแอปเรียกใช้ set()
,
setInexactRepeating()
หรือ setAndAllowWhileIdle()
การปลุกจะไม่ส่งเสียงก่อนเวลาทริกเกอร์ที่ระบุ
ใน Android 12 (API ระดับ 31) ขึ้นไป ระบบจะเรียกใช้สัญญาณเตือนภายใน 1 ชั่วโมงหลังจากเวลาทริกเกอร์ที่ระบุ เว้นแต่จะมีผลข้อจำกัดการประหยัดแบตเตอรี่ เช่น โหมดประหยัดแบตเตอรี่หรือ Doze
ส่งการแจ้งเตือนในช่วงเวลาหนึ่ง
หากแอปเรียกใช้ setWindow()
สัญญาณเตือนจะไม่ดังก่อนเวลาทริกเกอร์ที่ระบุ ระบบจะส่งเสียงปลุกภายในกรอบเวลาที่กำหนดโดยเริ่มตั้งแต่เวลาที่ทริกเกอร์ที่ระบุ เว้นแต่จะมีข้อจำกัดการประหยัดแบตเตอรี่
หากแอปกำหนดเป้าหมายเป็น Android 12 ขึ้นไป ระบบจะเลื่อนเวลาเรียกใช้การปลุกที่ไม่แน่นอนตามกรอบเวลาอย่างน้อย 10 นาที ด้วยเหตุนี้ ค่าพารามิเตอร์ windowLengthMillis
ภายใต้ 600000
จึงถูกตัดเป็น 600000
ส่งการแจ้งเตือนแบบซ้ำในช่วงเวลาที่ค่อนข้างสม่ำเสมอ
หากแอปเรียกใช้ setInexactRepeating()
ระบบจะเรียกใช้การแจ้งเตือนหลายรายการ ดังนี้
- การปลุกครั้งแรกจะดังขึ้นภายในกรอบเวลาที่กำหนด โดยเริ่มจากเวลาทริกเกอร์ที่ระบุ
- การปลุกที่ตามมามักจะส่งเสียงเตือนหลังจากผ่านกรอบเวลาที่ระบุไว้แล้ว ระยะเวลาระหว่างการเรียกใช้การปลุก 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
- ให้สิทธิ์โดยอัตโนมัติ
- ผู้ใช้เพิกถอนไม่ได้
- ขึ้นอยู่กับนโยบาย Google Play ที่กำลังจะเกิดขึ้น
- กรณีการใช้งานแบบจํากัด
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
ไปยังแอป แอปของคุณควรใช้ Broadcast Receiver ซึ่งทำสิ่งต่อไปนี้
- ยืนยันว่าแอปของคุณยังมีสิทธิ์เข้าถึงแอปพิเศษ โดยโทรไปที่
canScheduleExactAlarms()
การตรวจสอบนี้ช่วยปกป้องแอปของคุณในกรณีที่ผู้ใช้ให้สิทธิ์แก่แอปของคุณ แล้วเพิกถอนสิทธิ์นั้นเกือบจะทันที - กำหนดเวลาการปลุกในเวลาที่แน่นอนที่แอปของคุณต้องใช้ใหม่โดยอิงตามสถานะปัจจุบันของแอป
ตรรกะนี้ควรคล้ายกับสิ่งที่แอปทำเมื่อได้รับการออกอากาศ
ACTION_BOOT_COMPLETED
ขอให้ผู้ใช้ให้สิทธิ์ SCHEDULE_EXACT_ALARM
หากจำเป็น คุณสามารถส่งผู้ใช้ไปยังหน้าจอการปลุกและการช่วยเตือนในการตั้งค่าระบบได้ ดังที่แสดงในรูปที่ 1 โดยทำตามขั้นตอนต่อไปนี้
- ใน UI ของแอป ให้อธิบายให้ผู้ใช้ทราบว่าทำไมแอปจึงต้องตั้งเวลานาฬิกาปลุกดัง
- เรียกใช้ Intent ที่มีการดำเนินการของ Intent
ACTION_REQUEST_SCHEDULE_EXACT_ALARM
ตั้งปลุกซ้ำ
การปลุกซ้ำช่วยให้ระบบแจ้งเตือนแอปของคุณตามกำหนดการที่เกิดซ้ำได้
การปลุกที่ออกแบบมาไม่ดีอาจทำให้แบตเตอรี่หมดและทำให้เซิร์ฟเวอร์มีภาระงานมาก ด้วยเหตุนี้ ใน Android 4.4 (API ระดับ 19) ขึ้นไป การปลุกซ้ำทั้งหมดจึงเป็นการปลุกที่ไม่ถูกต้อง
การปลุกซ้ำมีลักษณะดังนี้
ประเภทการปลุก สำหรับการสนทนาเพิ่มเติม โปรดดูที่เลือกประเภทการปลุก
เวลาทริกเกอร์ หากเวลาทริกเกอร์ที่คุณระบุเป็นเวลาที่ผ่านมาแล้ว การปลุกจะทำงานทันที
ช่วงเวลาการปลุก เช่น วันละครั้ง ทุกชั่วโมง หรือทุก 5 นาที
ความตั้งใจที่รอดำเนินการที่จะเริ่มทำงานเมื่อมีการเรียกให้ปลุก เมื่อคุณตั้งปลุกครั้งที่ 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 น. และ repetir 1 ครั้งต่อวันในเวลาเดียวกัน
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
จะทำงานต่อไปได้โดยไม่ต้องให้ผู้ใช้รีสตาร์ทการแจ้งเตือนด้วยตนเอง
มีขั้นตอนดังนี้
ตั้งค่าสิทธิ์
RECEIVE_BOOT_COMPLETED
ในไฟล์ Manifest ของแอปพลิเคชัน ซึ่งจะช่วยให้แอปของคุณได้รับACTION_BOOT_COMPLETED
ที่ระบบประกาศหลังจากบูตเสร็จ (การดำเนินการนี้จะได้ผลก็ต่อเมื่อผู้ใช้เปิดแอปอย่างน้อย 1 ครั้งแล้วเท่านั้น)<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
ใช้
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. } } }
เพิ่มตัวรับลงในไฟล์ 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 ซึ่งช่วยยืดอายุการใช้งานแบตเตอรี่ของอุปกรณ์ การปลุกจะไม่ทำงานเมื่ออุปกรณ์อยู่ในโหมดสลีป ระบบจะเลื่อนการปลุกที่ตั้งเวลาไว้จนกว่าอุปกรณ์จะออกจากโหมดสลีป หากต้องการทำงานให้เสร็จสมบูรณ์แม้ในขณะที่อุปกรณ์ไม่ได้ใช้งาน คุณมีตัวเลือกหลายอย่างดังนี้
ใช้ WorkManager API ที่สร้างขึ้นเพื่อทำงานในเบื้องหลัง คุณสามารถระบุว่าระบบควรเร่งงานของคุณเพื่อให้งานเสร็จโดยเร็วที่สุด ดูข้อมูลเพิ่มเติมได้ที่หัวข้อตั้งเวลางานด้วย WorkManager
แนวทางปฏิบัติแนะนำ
ตัวเลือกที่คุณเลือกในการออกแบบการปลุกซ้ำอาจมีผลต่อวิธีที่แอปใช้ (หรือละเมิด) ทรัพยากรระบบ ตัวอย่างเช่น สมมติว่าแอปยอดนิยมที่ซิงค์กับเซิร์ฟเวอร์ หากการดำเนินการซิงค์อิงตามเวลาของนาฬิกาและอินสแตนซ์ทั้งหมดของแอปซิงค์กันในเวลา 23:00 น. ภาระงานในเซิร์ฟเวอร์อาจส่งผลให้เกิดความล่าช้าสูงหรือแม้แต่ "การปฏิเสธการให้บริการ" ทำตามแนวทางปฏิบัติแนะนำต่อไปนี้ในการใช้การปลุก
เพิ่มการสุ่ม (Jitter) ให้กับคำขอเครือข่ายที่ทริกเกอร์ขึ้นเนื่องจากการปลุกซ้ำ
ทำงานบางอย่างในเครื่องเมื่อระบบเปิดการแจ้งเตือน "งานในเครื่อง" หมายถึงการดำเนินการที่เข้าถึงเซิร์ฟเวอร์ไม่ได้หรือไม่ต้องการข้อมูลจากเซิร์ฟเวอร์
ในขณะเดียวกัน ให้ตั้งเวลาการปลุกที่มีคำขอเครือข่ายให้ทำงานเป็นช่วงๆ แบบสุ่ม
ตั้งความถี่การปลุกให้น้อยที่สุด
อย่าปลุกระบบอุปกรณ์โดยไม่จำเป็น (การทำงานนี้จะกำหนดโดยประเภทการปลุก ตามที่อธิบายไว้ในเลือกประเภทการปลุก)
อย่าตั้งค่าเวลาทริกเกอร์ของนาฬิกาปลุกให้แม่นยำเกินความจำเป็น
ให้ใช้
setInexactRepeating()
แทนsetRepeating()
เมื่อใช้setInexactRepeating()
Android จะซิงค์ข้อมูลการปลุกซ้ำจากหลายๆ แอป และจะทำให้การปลุกเกิดขึ้นพร้อมกัน ซึ่งจะช่วยลดจำนวนครั้งที่ระบบต้องปลุกอุปกรณ์ จึงช่วยประหยัดแบตเตอรี่ ตั้งแต่ Android 4.4 (API ระดับ 19) เป็นต้นไป การปลุกซ้ำทั้งหมดจะเป็นการปลุกที่ไม่แน่นอน โปรดทราบว่าแม้ว่าsetInexactRepeating()
จะมีประสิทธิภาพดีกว่าsetRepeating()
แต่ก็ยังอาจทำให้เซิร์ฟเวอร์ทำงานหนักเกินไปได้หากอินสแตนซ์ทั้งหมดของแอปเข้าถึงเซิร์ฟเวอร์ในเวลาใกล้เคียงกัน ดังนั้น สําหรับคําขอเครือข่าย ให้เพิ่มความสุ่มให้กับการแจ้งเตือนดังที่ได้กล่าวไว้ก่อนหน้านี้หลีกเลี่ยงการตั้งปลุกตามเวลาของนาฬิกา หากเป็นไปได้
การปลุกซ้ำที่อิงตามเวลาทริกเกอร์ที่แน่นอนจะปรับขนาดได้ไม่ดี ใช้
ELAPSED_REALTIME
หากทำได้ ประเภทต่างๆ ของการปลุกจะอธิบายไว้อย่างละเอียดในส่วนต่อไปนี้