AlarmManager) ช่วยให้คุณดำเนินการตามเวลาที่กำหนดนอกอายุการใช้งานของแอปพลิเคชันได้
ตัวอย่างเช่น คุณสามารถใช้การปลุกเพื่อเริ่มการดำเนินการที่ใช้เวลานาน เช่น การเริ่มบริการวันละครั้งเพื่อดาวน์โหลดพยากรณ์อากาศ
การปลุกมีลักษณะดังนี้
ซึ่งจะช่วยให้คุณเริ่ม Intent ตามเวลาและ/หรือช่วงเวลาที่กำหนดได้
คุณสามารถใช้การแจ้งเตือนร่วมกับ Broadcast Receiver เพื่อกำหนดเวลางานหรือ WorkRequest เพื่อดำเนินการอื่นๆ ได้
โดยจะทำงานนอกแอปพลิเคชัน คุณจึงใช้เพื่อทริกเกอร์เหตุการณ์หรือการดำเนินการได้แม้ว่าแอปจะไม่ได้ทำงานอยู่ และแม้ว่าอุปกรณ์จะอยู่ในโหมดสลีปก็ตาม
ซึ่งจะช่วยลดความต้องการทรัพยากรของแอป คุณสามารถกำหนดเวลาการดำเนินการได้โดยไม่ต้องพึ่งพาตัวจับเวลาหรือบริการที่ทำงานอย่างต่อเนื่อง
ตั้งการปลุกแบบไม่แน่นอน
เมื่อแอปตั้งการปลุกแบบไม่แน่นอน ระบบจะส่งการปลุก ณ เวลาใดเวลาหนึ่งในอนาคต การปลุกแบบไม่แน่นอนจะรับประกันเวลาในการส่งการปลุกในระดับหนึ่ง โดยยังคงปฏิบัติตามข้อจำกัดในการประหยัดแบตเตอรี่ เช่น 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 ของการปลุก หากต้องการทำงานขณะที่อุปกรณ์อยู่ในโหมด 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
- ให้สิทธิ์โดยอัตโนมัติ
- ผู้ใช้เพิกถอนไม่ได้
- ขึ้นอยู่กับนโยบายของ Google Play ที่กำลังจะมาถึง
- กรณีการใช้งานที่จำกัด
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 ที่ทำสิ่งต่อไปนี้
- ยืนยันว่าแอปของคุณยังมีสิทธิ์เข้าถึงแอปพิเศษอยู่ โดยโทรไปที่
canScheduleExactAlarms()การตรวจสอบนี้จะปกป้องแอปของคุณจากกรณีที่ผู้ใช้ให้สิทธิ์แก่แอป แล้วเพิกถอนสิทธิ์นั้นเกือบจะทันทีหลังจากนั้น - กำหนดเวลาใหม่สำหรับการปลุกเจาะจงที่แอปของคุณต้องการ โดยอิงตามสถานะปัจจุบัน
ตรรกะนี้ควรคล้ายกับสิ่งที่แอปทำเมื่อได้รับการออกอากาศ
ACTION_BOOT_COMPLETED
ขอให้ผู้ใช้ให้สิทธิ์ SCHEDULE_EXACT_ALARM
หากจำเป็น คุณสามารถส่งผู้ใช้ไปยังหน้าจอการปลุกและการช่วยเตือนในการตั้งค่าระบบได้ ดังที่แสดงในรูปที่ 1 โดยทำตามขั้นตอนต่อไปนี้
- ใน UI ของแอป ให้อธิบายแก่ผู้ใช้ถึงสาเหตุที่แอปของคุณต้องตั้งเวลาการปลุกแบบเจาะจง
- เรียกใช้ 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 จะยังคงทำงานต่อไปโดยที่ผู้ใช้ไม่ต้องรีสตาร์ทการปลุกด้วยตนเอง
มีขั้นตอนดังนี้
ตั้งค่าสิทธิ์
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. } } }
เพิ่ม 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 หากคุณต้องการทำงานให้เสร็จแม้ในขณะที่อุปกรณ์ไม่มีการใช้งาน ก็มีตัวเลือกหลายรายการให้เลือกใช้ ดังนี้
ตั้งสัญญาณปลุกเจาะจง
ใช้ WorkManager API ซึ่งสร้างขึ้นเพื่อทำงานในเบื้องหลัง คุณสามารถระบุว่าระบบควรเร่งงานของคุณเพื่อให้งานเสร็จเร็วที่สุด ดูข้อมูลเพิ่มเติมได้ที่หัวข้อกำหนดเวลางานด้วย WorkManager
แนวทางปฏิบัติแนะนำ
ทุกตัวเลือกที่คุณเลือกในการออกแบบการปลุกซ้ำอาจส่งผลต่อวิธีที่แอปใช้ (หรือละเมิด) ทรัพยากรระบบ ตัวอย่างเช่น สมมติว่ามีแอปยอดนิยมที่ซิงค์กับเซิร์ฟเวอร์ หากการซิงค์อิงตามเวลา และทุกอินสแตนซ์ของแอปซิงค์พร้อมกันตอน 23:00 น. โหลดบนเซิร์ฟเวอร์อาจส่งผลให้เกิดเวลาในการตอบสนองสูงหรือแม้แต่ "การปฏิเสธการให้บริการ" ทำตามแนวทางปฏิบัติแนะนำต่อไปนี้ในการใช้การปลุก
เพิ่มความสุ่ม (ความผันผวน) ให้กับคำขอเครือข่ายที่ทริกเกอร์อันเป็นผลมาจากการปลุกซ้ำ โดยทำดังนี้
ทำงานในเครื่องเมื่อมีการทริกเกอร์การปลุก "งานในเครื่อง" หมายถึงสิ่งใดก็ตามที่ไม่เข้าถึงเซิร์ฟเวอร์หรือไม่ต้องการข้อมูลจากเซิร์ฟเวอร์
ในขณะเดียวกัน ให้ตั้งเวลาการปลุกที่มีคำขอเครือข่ายให้เริ่มทำงานในช่วงเวลาแบบสุ่ม
ตั้งความถี่ในการปลุกให้น้อยที่สุด
อย่าปลุกอุปกรณ์โดยไม่จำเป็น (ลักษณะการทำงานนี้กำหนดโดยประเภทการปลุกตามที่อธิบายไว้ในเลือกประเภทการปลุก)
อย่าทำให้เวลาทริกเกอร์ของการปลุกแม่นยำเกินความจำเป็น
ใช้
setInexactRepeating()แทนsetRepeating()เมื่อคุณใช้setInexactRepeating()Android จะซิงค์การปลุกซ้ำจากหลายแอปและส่งสัญญาณเตือนพร้อมกัน ซึ่งจะช่วยลดจำนวนครั้งทั้งหมดที่ระบบต้องปลุกอุปกรณ์ จึงช่วยลดการใช้แบตเตอรี่ ตั้งแต่ Android 4.4 (ระดับ API 19) เป็นต้นไป การปลุกซ้ำทั้งหมดจะเป็นการปลุกแบบไม่แน่นอน โปรดทราบว่าแม้ว่าsetInexactRepeating()จะเป็นการปรับปรุงจากsetRepeating()แต่ก็ยังอาจทำให้เซิร์ฟเวอร์ทำงานหนักเกินไปได้หากทุกอินสแตนซ์ของแอปเข้าถึงเซิร์ฟเวอร์พร้อมกัน ดังนั้น สำหรับคำขอเครือข่าย ให้เพิ่มการสุ่มลงในการปลุกตามที่ได้กล่าวถึงก่อนหน้านี้หลีกเลี่ยงการตั้งการปลุกตามเวลาบนนาฬิกา หากเป็นไปได้
การปลุกซ้ำที่อิงตามเวลาทริกเกอร์ที่แน่นอนจะปรับขนาดได้ไม่ดีนัก ใช้
ELAPSED_REALTIMEหากทำได้ ประเภทสัญญาณเตือนต่างๆ มีคำอธิบายโดยละเอียดในส่วนต่อไปนี้