AlarmManager เป็นบริการระบบ Android ที่ช่วยให้แอปพลิเคชันทำงานตามเวลาที่กำหนดได้ แม้ว่าแอปพลิเคชันจะไม่ได้ทำงานอยู่หรืออุปกรณ์อยู่ในโหมดสลับก็ตาม แตกต่างจาก JobScheduler หรือ WorkManager ตรงที่ AlarmManager รับประกันความแม่นยำในการเรียกใช้ ทำให้เป็นสิ่งที่ขาดไม่ได้สำหรับการปลุก การเตือนในปฏิทิน และงานที่สำคัญต่อเวลาในการทำงาน ตาม Android Developers, 2026 ตั้งแต่ Android 4.4 เป็นต้นไป setRepeating จะทำงานเป็นการทำซ้ำที่ไม่แม่นยำ และการปลุกที่แม่นยำจำเป็นต้องใช้ setExact หรือ setAlarmClock
ประเด็นสำคัญ
AlarmManager เป็นบริการระบบ Android ที่ให้ API สำหรับกำหนดเวลาทำงานด้วยเวลาที่แม่นยำหรือโดยประมาณ มีมาตั้งแต่ Android เวอร์ชันแรกและยังคงเป็นวิธีที่เชื่อถือได้เพียงวิธีเดียวในการเรียกใช้โค้ด ณ เวลาที่กำหนด โดยไม่ขึ้นกับสถานะของแอปพลิเคชันและอุปกรณ์
หลักการทำงานเรียบง่าย: แอปพลิเคชันส่ง PendingIntent ไปยังระบบพร้อมกับเวลาที่กำหนด เมื่อถึงเวลาที่กำหนด ระบบจะส่ง Intent ไปยัง BroadcastReceiver ที่ลงทะเบียนไว้หรือเริ่ม Service แม้ว่าอุปกรณ์จะอยู่ในโหมดสลับ WakeLock ก็ช่วยให้โปรเซสเซอร์ตื่นขึ้นและประมวลผลเหตุการณ์ได้
พื้นที่การใช้งานหลัก ของ AlarmManager คืองานที่ต้องการเวลาที่แม่นยำ: การปลุก การเตือนในปฏิทิน การเริ่มดำเนินการระยะยาวในเวลาที่กำหนด สำหรับงานที่ความแม่นยำไม่สำคัญ (การซิงค์รายวัน) Google แนะนำ WorkManager หรือ JobScheduler เนื่องจากประหยัดพลังงานมากกว่า
AlarmManager รับ PendingIntent และเวลาเรียกใช้จากแอปพลิเคชัน ระบบบันทึกคำขอนี้ในตัวกำหนดเวลาภายในและปลุกโปรเซสเซอร์ตามเวลาที่กำหนดเพื่อส่ง Intent นักพัฒนาต้องลงทะเบียน BroadcastReceiver ล่วงหน้าเพื่อจัดการ Intent นี้
AlarmManager รองรับการปลุก 4 ประเภท: ELAPSED_REALTIME (เวลาตั้งแต่บูต ไม่ปลุก), RTC (เวลาจริง ไม่ปลุก), ELAPSED_REALTIME_WAKEUP (เวลาตั้งแต่บูต ปลุกอุปกรณ์) และ RTC_WAKEUP (เวลาจริง ปลุก) เวอร์ชัน WAKEUP จำเป็นหากต้องทำงานแม้อุปกรณ์อยู่ในโหมดหลับ
| ประเภท | เวลา | ปลุก | ตัวอย่าง |
|---|---|---|---|
| ELAPSED_REALTIME | ตั้งแต่บูต | ไม่ | ตัวจับเวลาใช้งาน |
| RTC | การประทับเวลา Unix | ไม่ | การบันทึก |
| ELAPSED_REALTIME_WAKEUP | ตั้งแต่บูต | ใช่ | งานประจำ |
| RTC_WAKEUP | การประทับเวลา Unix | ใช่ | นาฬิกาปลุก |
ตั้งแต่ Android 12 (API 31) การใช้การปลุกที่แม่นยำ (setExact) จำเป็นต้องมีสิทธิ์ SCHEDULE_EXACT_ALARM ผู้ใช้สามารถเพิกถอนได้ผ่านการตั้งค่า สำหรับแอปพลิเคชันที่ต้องการการปลุกที่แม่นยำพร้อมการแสดงผล (เช่น แอปนาฬิกา) จะใช้ USE_EXACT_ALARM ซึ่งให้มาตอนติดตั้ง
AlarmManager มีสามเมธอดหลักสำหรับกำหนดเวลาทำงาน การเลือกเมธอดจะกำหนดความแม่นยำในการเรียกใช้และผลกระทบต่อการใช้พลังงานของอุปกรณ์
set — เมธอดพื้นฐานสำหรับการเรียกใช้ครั้งเดียวที่ไม่แม่นยำ ระบบอาจเลื่อนเวลาได้ถึงสองสามนาทีเพื่อจัดกลุ่มกับเหตุการณ์อื่น เหมาะสำหรับงานที่ความแม่นยำไม่สำคัญ: การเตือนให้เปิดแอปพลิเคชัน
setRepeating — เมธอดสำหรับการทำซ้ำเป็นระยะ ตั้งแต่ Android 4.4 (API 19) setRepeating ไม่แม่นยำอีกต่อไป — ช่วงเวลาอาจแตกต่างกันไป ระบบไม่รับประกันช่วงเวลาคงที่อีกต่อไป แทนที่จะใช้ setRepeating แนะนำให้ใช้ setExact พร้อมกำหนดเวลาใหม่หรือ WorkManager พร้อม PeriodicWorkRequest
setExact — เมธอดสำหรับการเรียกใช้ครั้งเดียวที่แม่นยำ ระบบจะปลุกอุปกรณ์ให้ใกล้เคียงกับเวลาที่กำหนดมากที่สุด setAlarmClock เป็นกรณีพิเศษของ setExact ที่แสดงไอคอนปลุกในแถบสถานะและมีลำดับความสำคัญสูงสุดในบรรดาการปลุกทุกประเภท
val alarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
// การปลุกครั้งเดียวที่แม่นยำ
val intent = Intent(this, AlarmReceiver::class.java)
val pendingIntent = PendingIntent.getBroadcast(
this, 0, intent,
PendingIntent.FLAG_IMMUTABLE
)
alarmManager.setAlarmClock(
AlarmManager.AlarmClockInfo(
targetTime, pendingIntent
),
pendingIntent
)
สถานการณ์ทั่วไป คือการสร้างการเตือนรายวันตามเวลาที่กำหนด โดยใช้ RTC_WAKEUP พร้อม setExact เพื่อจุดประสงค์นี้ เมื่อถูกเรียกใช้ BroadcastReceiver จะเริ่มการแจ้งเตือนหรือ Service หลังจากการประมวลผล ต้องกำหนดเวลางานใหม่สำหรับวันถัดไป
class ReminderReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent?) {
val notificationManager =
context.getSystemService(Context.NOTIFICATION_SERVICE)
as NotificationManager
val notification = NotificationCompat.Builder(
context, "reminder_channel"
)
.setContentTitle("การเตือน")
.setContentText("ถึงเวลาทำงานให้เสร็จ")
.setSmallIcon(R.drawable.ic_reminder)
.build()
notificationManager.notify(1001, notification)
}
}
สำหรับการทำซ้ำรายวัน จะใช้ setExact พร้อมการคำนวณเวลาเรียกใช้ถัดไป สามารถส่งแฟล็กใน Intent เพื่อระบุประเภทการเตือนต่างๆ ตรวจสอบให้แน่ใจว่า BroadcastReceiver ลงทะเบียนใน AndroidManifest.xml พร้อมการจัดการการดำเนินการ WAKEUP
fun scheduleDailyReminder(context: Context, hour: Int, minute: Int) {
val calendar = Calendar.getInstance().apply {
set(Calendar.HOUR_OF_DAY, hour)
set(Calendar.MINUTE, minute)
set(Calendar.SECOND, 0)
if (before(Calendar.getInstance())) {
add(Calendar.DAY_OF_MONTH, 1)
}
}
val alarmManager =
context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
alarmManager.setExactAndAllowWhileIdle(
AlarmManager.RTC_WAKEUP,
calendar.timeInMillis,
pendingIntent
)
}
AlarmManager เป็นเครื่องมือที่ทรงพลังแต่ใช้พลังงานมาก การปลุก WAKEUP แต่ละครั้งจะนำอุปกรณ์ออกจากโหมดสลับ ทำให้สิ้นเปลืองแบตเตอรี่ Google แนะนำให้ลดการใช้การปลุกที่แม่นยำและเลือกใช้ setExactAndAllowWhileIdle บน Android 6+ เพื่อลดผลกระทบต่อ Doze Mode สำหรับงานประจำที่ไม่ต้องการความแม่นยำ ให้ใช้ WorkManager พร้อม PeriodicWorkRequest ซึ่งไม่ต้องปลุกอุปกรณ์และไม่ทำให้แบตเตอรี่หมดในแต่ละครั้งที่ทำงาน
สำหรับการทดสอบ AlarmManager ให้ใช้ TestAlarmManager จาก Android Test Framework ซึ่งช่วยจำลองการเรียกใช้การปลุกโดยไม่ต้องรอเวลาจริง Robolectric มี ShadowAlarmManager ที่สกัดกั้นการเรียก set, setExact และ setRepeating โดยให้เมธอดสำหรับการบังคับเรียกใช้และการตรวจสอบจำนวนงานที่กำหนดไว้ สำหรับ Unit Test ของ BroadcastReceiver ให้ใช้ Robolectric.getForegroundScheduler() นอกจากนี้ยังมีการทดสอบ Espresso พร้อม IdlingResource ที่รอการเรียกใช้การปลุกในการทดสอบแบบบูรณาการ
หากแอปพลิเคชันของคุณใช้ AlarmManager สำหรับงานประจำที่ไม่ต้องการเวลาที่แม่นยำ ให้พิจารณาย้ายไปยัง WorkManager PeriodicWorkRequest ที่มีช่วงเวลาขั้นต่ำ 15 นาทีแทนที่ setRepeating ในขณะที่ WorkManager รับประกันการทำงานหลังรีบูต จัดการ Doze Mode และไม่ต้องการสิทธิ์ SCHEDULE_EXACT_ALARM สำหรับงานที่สำคัญต่อเวลา (ปลุกตอน 7 โมงเช้า) AlarmManager ยังคงเป็นตัวเลือกที่ถูกต้องเท่านั้น กลยุทธ์ที่ดีที่สุดคือใช้ AlarmManager เฉพาะการปลุกด้วย setAlarmClock และย้ายงานพื้นหลังอื่นๆ ทั้งหมดไปยัง WorkManager
สำหรับงานประจำที่ไม่ต้องการความแม่นยำ ให้ใช้ WorkManager พร้อม PeriodicWorkRequest สำหรับงานที่มีเวลาที่แม่นยำแต่ไม่สำคัญที่จะต้องเรียกใช้ในโหมดสลับ — ให้ใช้ setExact โดยไม่มี WAKEUP และเฉพาะการปลุกที่ต้องปลุกเท่านั้น — ให้ใช้ setAlarmClock หรือ RTC_WAKEUP
สิ่งสำคัญคือต้องตรวจสอบสิทธิ์ SCHEDULE_EXACT_ALARM บน Android 12+ หากไม่ได้รับสิทธิ์ setExact จะทำงานเหมือน set ทั่วไป (ไม่แม่นยำ) ใช้ AlarmManager.canScheduleExactAlarms() เพื่อตรวจสอบ หากไม่มีสิทธิ์ คุณสามารถแจ้งให้ผู้ใช้ไปที่การตั้งค่าผ่าน Intent(Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM)
คุณสมบัติที่สำคัญอย่างยิ่งของ AlarmManager — การปลุกที่กำหนดไว้ทั้งหมดจะถูกรีเซ็ตหลังจากรีสตาร์ทอุปกรณ์ เพื่อกู้คืนการปลุกเหล่านี้ คุณต้องประกาศ BroadcastReceiver ที่จัดการ Intent.ACTION_BOOT_COMPLETED และกำหนดเวลาการปลุกที่ใช้งานอยู่ทั้งหมดใหม่ในเมธอด onReceive หากไม่ดำเนินการนี้ ผู้ใช้จะสูญเสียการเตือนทั้งหมดหลังจากปิดและเปิดโทรศัพท์
class BootReceiver : BroadcastReceiver() {
override fun onReceive(
context: Context,
intent: Intent
) {
if (intent.action ==
Intent.ACTION_BOOT_COMPLETED
) {
val prefs =
context.getSharedPreferences("alarms", 0)
val savedTime =
prefs.getLong("next_alarm", 0L)
if (savedTime > System.currentTimeMillis()) {
scheduleReminder(context, savedTime)
}
}
}
}
ในทางปฏิบัติ AlarmManager ยังคงเป็นโซลูชันที่ดีที่สุดสำหรับแอปพลิเคชันนาฬิกาปลุก ปฏิทิน การเตือนกินยา และงานใดๆ ที่เวลาในการทำงานมีความสำคัญต่อผู้ใช้ สำหรับสถานการณ์งานพื้นหลังอื่นๆ ทั้งหมด WorkManager หรือ JobScheduler เป็นที่นิยมกว่า
เมื่อเลือกระหว่าง AlarmManager และ WorkManager ให้ปฏิบัติตามกฎนี้: หากผู้ใช้ขอให้เตือนเวลาบ่าย 2:30 อย่างชัดเจน — ให้ใช้ AlarmManager พร้อม setAlarmClock หากงานควรทำงาน “ประมาณครั้งละหนึ่งชั่วโมง” — WorkManager พร้อม PeriodicWorkRequest จะประหยัดพลังงานและเชื่อถือได้มากกว่า
คำถามที่พบบ่อย
ทั้งสองเมธอดรับประกันการเรียกใช้ที่แม่นยำ แต่ setAlarmClock จะแสดงไอคอนปลุกในแถบสถานะเพิ่มเติมและแจ้งระบบว่าเป็นการปลุกของผู้ใช้ บน Android 6+ setAlarmClock มีภูมิคุ้มกันจาก Doze Mode ในขณะที่ setExact อาจล่าช้า
หลังจากรีสตาร์ท การปลุกที่กำหนดไว้ทั้งหมดจะถูกรีเซ็ต เพื่อกู้คืนการปลุกเหล่านี้ คุณต้องลงทะเบียน BroadcastReceiver สำหรับการดำเนินการ BOOT_COMPLETED และกำหนดเวลางานทั้งหมดใหม่ใน onReceive หากไม่ดำเนินการนี้ จะไม่มีการปลุกใดๆ เกิดขึ้นหลังจากเปิดอุปกรณ์
ตั้งแต่ API 19 setRepeating ไม่แม่นยำอีกต่อไป — ระบบอาจเลื่อนช่วงเวลาเพื่อประหยัดพลังงาน ให้ใช้ setExact พร้อมกำหนดเวลาใหม่ด้วยตนเอง หรือ WorkManager พร้อม PeriodicWorkRequest ซึ่งให้พฤติกรรมที่คาดเดาได้มากกว่า
สำหรับ setExact จำเป็นต้องมีสิทธิ์ SCHEDULE_EXACT_ALARM ซึ่งผู้ใช้สามารถให้หรือเพิกถอนได้ในการตั้งค่า สำหรับ setAlarmClock พร้อมการแสดงผลอินเทอร์เฟซนาฬิกา จะใช้ USE_EXACT_ALARM ซึ่งให้โดยอัตโนมัติเมื่อติดตั้งจากร้านค้า
ไม่ AlarmManager ทำงานผ่าน PendingIntent เสมอ อาจเป็น PendingIntent.getBroadcast สำหรับ BroadcastReceiver, PendingIntent.getService สำหรับ Service หรือ PendingIntent.getActivity สำหรับ Activity หากไม่มี PendingIntent ระบบจะไม่สามารถส่งเหตุการณ์ไปยังแอปพลิเคชันได้
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ