Alarm Manager란 말 그대로 설정한 시간에 설정한 작업을 수행할 수 있는 기능이다.
즉, 특정 시간에 앱을 사용하지 않아도 어떠한 작업을 할 수 있게 해주는 기능이며 특징은 다음과 같다.
- 지정된 시간에 또는 정해진 간격으로 인텐트를 실행
- Broadcast receiver와 함께 알람을 사용하여 서비스를 시작하고 다른 작업을 실행할 수 있다.
- 애플리케이션 외부에서 작동하므로 알람을 사용하면 앱이 실행 중이 아니거나 기기가 대기 상태인 경우에도 이벤트나 작업을 트리거할 수 있다.
- 알람은 앱의 리소스 요구사항을 최소화하는 데 도움이 됩니다. 타이머 또는 계속 실행 중인 백그라운드 서비스를 사용하지 않고 작업을 예약할 수 있다.
이외의 권장사항 또는 장단점은 공식문서를 참고 바랍니다.
https://developer.android.com/training/scheduling/alarms?hl=ko
사용 방법
1. 옵션
Alarm manager에는 몇가지 옵션들이 있다.
그 중 대표적인 옵션 2개만 정의하며, 보다 자세한 내용은 다음 공식문서를 참고 바랍니다.
https://developer.android.com/develop/background-work/services/alarms/schedule?hl=ko#inexact
Doze 모드 : 충전중이지 않으며, 화면이 꺼진상태로 장시간 대기중인 상태 또는 절전 모드
- setInexactRepeating()
주기적인 시간 단위( ex. 1시간 마다)로 반복 알람
해당 옵션은 Doze모드일 때에는 동작하지 않는다.
public void setInexactRepeating (
int type, // 알람 유형
long triggerAtMillis, // 트리거 시간
long intervalMillis, // 알람 간격
PendingIntent operation // 인텐트
)
- setExactAndAllowWhileIdle()
정확한 알림 시간을 보장하며, Doze모드일 때에도 동작한다.
public void setExactAndAllowWhileIdle (
int type, // 알람 유형
long triggerAtMillis, // 트리거 시간
PendingIntent operation // 인텐트
)
그러나 Doze모드가 장시간 지속될 경우 운영체제에서 알림 시간을 변경할 수 있어 다음날 제시간에 알림이 안올 경우가 있다.
- AlarmClock()
AlarmManager.AlarmClockInfo(long triggerTime, PendingIntent showIntent)
AlarmManager.setAlarmClock(AlarmClockInfo, PendingIntent)
AlarmClock은 setExactAndAllowWhileIdle()와 비슷한 기능을 제공하며, Doze모드도 깨우는 기능이 탑재되어 있다.
그러나 반복 기능은 제공되지 않는 일회성 알림으로, 한 번 설정한 알림이 울리면 다음엔 울리지 않는다.
2. 알람 유형
- ELAPSED_REALTIME : 기기 부팅 시간 기준으로 대기 중인 Intent 실행, 절전모드는 해제하지 않는다.
- ELAPSED_REALTIME_WAKEUP : 위와 동일하나 절전모드는 해제
- RTC : 지정된 시간에 대기 중인 Intent 실행, 절전모드는 해제하지 않는다.
- RTC_WAKEUP : 위와 동일하나 절전모드는 해제
3. 코드
Alarm.kt
class Alarm(private val context: Context) {
private val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as? AlarmManager
fun setAlarm(hour : Int, minute : Int, alarm_code : Int, content : String, checkedDayList:MutableList<Boolean>){
val intent = Intent(context, AlarmReceiver::class.java).apply {
putExtra("alarm_rqCode", alarm_code)
putExtra("content", content)
putExtra("checkedDayList", checkedDayList.toBooleanArray())
}
// 알람 동작 시 실행 할 인텐트
val pendingIntent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S){
PendingIntent.getBroadcast(context,alarm_code,intent,PendingIntent.FLAG_IMMUTABLE)
}else{
PendingIntent.getBroadcast(context,alarm_code,intent,PendingIntent.FLAG_UPDATE_CURRENT)
}
// 트리거 시간 ( 실제 시간 )
val calendar : Calendar = Calendar.getInstance().apply {
timeInMillis = System.currentTimeMillis()
set(Calendar.HOUR_OF_DAY, hour)
set(Calendar.MINUTE, minute)
set(Calendar.SECOND, 0)
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
alarmManager?.setExactAndAllowWhileIdle(
AlarmManager.RTC_WAKEUP,
calendar.timeInMillis,
pendingIntent
)
//val alarmClock = AlarmManager.AlarmClockInfo(calendar.timeInMillis, pendingIntent)
//alarmManager?.setAlarmClock(alarmClock, pendingIntent)
}
}
fun cancelAlarm(alarm_code : Int){
val intent = Intent(context, AlarmReceiver::class.java)
val pendingIntent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S){
PendingIntent.getBroadcast(context,alarm_code,intent,PendingIntent.FLAG_IMMUTABLE)
}else{
PendingIntent.getBroadcast(context,alarm_code,intent,PendingIntent.FLAG_UPDATE_CURRENT)
}
alarmManager?.cancel(pendingIntent)
}
}
Alarm Manager를 통해 작업을 예약하였다면, 예약 시간에 등록해 두었던 인텐트가 실행된다.
여기서의 인텐트는 AlarmReceiver.kt 이며, 코드는 지정해 놓은 시간에 해야할 일을 알람으로 알려주는 코드다.
여기서는 본인이 해야 할 작업에 대한 코드를 작성해 주면 된다.
AlarmReceiver.kt
class AlarmReceiver : BroadcastReceiver() {
private val CHANNEL_ID = "TodayAlarm"
private val CHANNEL_NAME = "Alarm"
override fun onReceive(context: Context?, intent: Intent?) {
val today = Calendar.getInstance().get(Calendar.DAY_OF_WEEK)
val checkedDayList = intent?.extras!!.getBooleanArray("checkedDayList")
if(!checkedDayList!![today-1]) return
val notificationManager: NotificationManager =
context?.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val importance = NotificationManager.IMPORTANCE_DEFAULT
notificationManager.createNotificationChannel(
NotificationChannel(CHANNEL_ID, CHANNEL_NAME, importance)
)
}
val intent2 = Intent(context, AlarmService::class.java)
val requestCode = intent.extras!!.getInt("alarm_rqCode")
val content = intent.extras!!.getString("content")
val pendingIntent =
if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.S)
PendingIntent.getActivity(context,requestCode,intent2,PendingIntent.FLAG_IMMUTABLE)
else PendingIntent.getActivity(context,requestCode,intent2,PendingIntent.FLAG_UPDATE_CURRENT);
val builder = NotificationCompat.Builder(context, CHANNEL_ID)
.setSmallIcon(R.mipmap.todo_icon)
.setContentTitle("정각에 해야지")
.setContentText(content)
.setAutoCancel(false)
.setShowWhen(true)
.setColor(ContextCompat.getColor(context, R.color.purple_200))
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setContentIntent(pendingIntent)
.build()
notificationManager.notify(1, builder)
}
}
'안드로이드 > 안드로이드' 카테고리의 다른 글
[안드로이드] Permission (TedPermission) 권한 요청 (0) | 2024.02.29 |
---|---|
[안드로이드] BottomSheetDialog (0) | 2024.02.29 |
[안드로이드] SharedPreferences (0) | 2023.11.29 |
[안드로이드] MyApplication (1) | 2023.11.26 |
[안드로이드] 백그라운드에서 위치 데이터 지속적으로 얻기 (1) | 2023.11.26 |