AlarmManager
) ช่วยให้คุณดำเนินการตามเวลานอกอายุการใช้งานของแอปพลิเคชันได้
ตัวอย่างเช่น คุณอาจใช้การปลุกเพื่อเริ่มการดำเนินการที่ใช้เวลานาน เช่น การเริ่มบริการวันละครั้งเพื่อดาวน์โหลดพยากรณ์อากาศ
สัญญาณเตือนมีลักษณะดังนี้
ซึ่งช่วยให้คุณเรียกใช้ Intent ในเวลาและ/หรือช่วงเวลาที่กำหนด
คุณสามารถใช้ร่วมกับตัวรับการออกอากาศเพื่อกำหนดเวลางานหรือคำของานเพื่อดำเนินการอื่นๆ ได้
เหตุการณ์ทำงานนอกแอปพลิเคชัน คุณจึงใช้เหตุการณ์เพื่อทริกเกอร์เหตุการณ์หรือการดําเนินการได้แม้ว่าแอปจะไม่ทํางานอยู่และอุปกรณ์จะอยู่ในโหมดสลีปก็ตาม
ซึ่งจะช่วยคุณลดข้อกำหนดด้านทรัพยากรของแอป คุณสามารถกำหนดเวลาการดำเนินการโดยไม่ต้องใช้ตัวจับเวลาหรือบริการที่ทำงานอย่างต่อเนื่อง
ตั้งปลุกแบบไม่แน่นอน
เมื่อแอปตั้งการปลุกที่ไม่ถูกต้อง ระบบจะส่งการปลุกในช่วงเวลาหนึ่งในอนาคต การปลุกที่ไม่แน่นอนจะรับประกันบางอย่างเกี่ยวกับเวลาในการส่งการปลุก ขณะเดียวกันก็เคารพข้อจำกัดในการประหยัดแบตเตอรี่ เช่น โหมดสลีป
นักพัฒนาแอปสามารถใช้การรับประกัน API ต่อไปนี้เพื่อปรับแต่งเวลาในการส่งการแจ้งเตือนที่ไม่ถูกต้อง
ส่งการปลุกหลังเวลาที่กำหนด
หากแอปเรียกใช้ set()
,
setInexactRepeating()
หรือ setAndAllowWhileIdle()
ระบบจะไม่ปลุกก่อนเวลาทริกเกอร์ที่ระบุ
ใน Android 12 (API ระดับ 31) ขึ้นไป ระบบจะเรียกใช้การปลุกภายใน 1 ชั่วโมงนับจากเวลาที่ทริกเกอร์ที่ระบุ เว้นแต่จะมีการใช้ข้อจำกัดการประหยัดแบตเตอรี่ เช่น โหมดประหยัดแบตเตอรี่หรือโหมดสลีป
ส่งสัญญาณเตือนในกรอบเวลา
หากแอปเรียกใช้ 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
เช่น ด้วย 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 นาที
ความตั้งใจที่รอดำเนินการที่จะเริ่มทำงานเมื่อมีการเรียกให้ปลุก เมื่อคุณตั้งปลุกครั้งที่ 2 ที่ใช้ Intent ที่รอดำเนินการเดียวกัน ปลุกครั้งที่ 2 จะแทนที่การปลุกเดิม
หากต้องการยกเลิก 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 วินาที) เนื่องจากไม่ได้รับผลกระทบจากเขตเวลาหรือภาษา นาฬิกาแบบเรียลไทม์เหมาะสําหรับการปลุกที่ขึ้นอยู่กับภาษาปัจจุบันมากกว่า
ทั้งสองประเภทจะมีเวอร์ชัน "Wakeup" ซึ่งใช้ชื่อว่าปลุก 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 ครั้ง (แบบไม่ซ้ำ) ใน 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. } } }
เพิ่มตัวรับสัญญาณลงในไฟล์ 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()
instead ofsetRepeating()
เมื่อคุณใช้setInexactRepeating()
ระบบ Android จะซิงค์การปลุกซ้ำจากหลายแอปและเปิดการปลุกพร้อมกัน ซึ่งจะช��วยลดจำนวนครั้งที่ระบบต้องปลุกอุปกรณ์ จึงช่วยประหยัดแบตเตอรี่ ตั้งแต่ Android 4.4 (API ระดับ 19) การปลุกซ้ำทั้งหมดจะเป็นการปลุกที่ไม่แน่นอน โปรดทราบว่าแม้ว่าsetInexactRepeating()
จะมีประสิทธิภาพดีกว่าsetRepeating()
แต่ก็ยังอาจทำให้เซิร์ฟเวอร์ทำงานหนักเกินไปได้หากอินสแตนซ์ทั้งหมดของแอปเข้าถึงเซิร์ฟเวอร์ในเวลาใกล้เคียงกัน ดังนั้น สําหรับคําขอเครือข่าย ให้เพิ่มความสุ่มให้กับการแจ้งเตือนดังที่ได้กล่าวไว้ก่อนหน้านี้หลีกเลี่ยงการตั้งปลุกตามเวลาของนาฬิกา หากเป็นไปได้
การปลุกซ้ำที่อิงตามเวลาทริกเกอร์ที่แน่นอนจะปรับขนาดได้ไม่ดี ใช้
ELAPSED_REALTIME
หากทำได้ ประเภทต่างๆ ของการปลุกจะอธิบายไว้อย่างละเอียดในส่วนต่อไปนี้