본문 바로가기
프로그래밍/Android

[Android] AlarmManager

by Youngs_ 2023. 11. 24.

AlarmManager

AlarmManager는 특정한 시간과 주기로 Intent를 실행하는 기능을 제공한다.

예를 들어, 정해진 시간에 사용자에게 Notification을 보내려고 할 때 AlarmManager를 활용할 수 있다.

원하는 시간에 AlarmManager를 통해 broadcast를 전송하도록 구현하고, 그 broadcast를 받은 receiver는 Notification을 발행하도록 구현하면 된다.

자세한 방법은 다음 포스팅으로 업로드할 예정이다.

 

이 포스팅에서는 AlarmManager의 특징과 장단점, 구현 방법 등에 대해서 알아보자.

 

 

 

특징

  • 지정된 시간과 간격으로 Intent를 실행한다.
  • 애플리케이션 외부에서 작동한다. 따라서 앱을 실행하고 있지 않을 때나 Doze 모드인 경우(Doze 모드를 깨우고) 특정 이벤트를 트리거할 수 있다. (Doze 모드는 절전 모드와 비슷한 개념)
  • 리소스를 효율적으로 사용할 수 있다. 애플리케이션 내의 백그라운드 서비스를 사용하지 않고, 안드로이드 시스템의 백그라운드를 사용하기 때문이다.

 

만약 AlarmManager를 통해 지정된 시간에 서버에 접근하는 등의 네트워크 작업을 작동시키려고 한다면, 배터리 소모가 발생하고 서버에 부담을 줄 수 있다. 

앱 데이터를 호스팅하는 서버를 보유하고 있다면 동기화 어댑터와 GCM를 사용하는 것이 더 효율적인 방법이라고 한다.

 

 

 

 

구현 방법

  1. AlarmManager 시간 유형
  2. 알람 발생 시간
  3. 시간 간격
  4. 알람 발생시 트리거 될 인텐트

일정 주기로 AlarmManager의 알람을 작동시키기 위해서는 위 네 가지의 항목이 인자로 들어간다.

(* 여기서 알람 발생은, Notification의 의미가 아닌 Event의 의미와 유사함)

 

 

AlarmManager 시간 유형

  시간 기준 Doze 모드인 경우 이벤트 발생 여부
ELAPSED_REALTIME 기기가 부팅된 후 경과한 시간 기준 X
ELAPSED_REALTIME_WAKEUP 기기가 부팅된 후 경과한 시간 기준 O
RTC 실제 시간 기준 X
RTC_WAKEUP 실제 시간 기준 O

 

WAKEUP 버전인 경우, 기기가 Doze 모드여도 예약된 시간에 근접하게 알람을 발생시킬 수 있다.

반면에 WAKEUP 버전이 아니면 기기가 Doze 모드인 경우 예약된 시간과 다르게, 기기가 켜지고 Doze 모드가 해제되었을 때 알람을 발생시킨다.

 

일반적으로 특정 간격으로 알람을 발생시킨다면 ELAPSED_REALTIME 모드를 사용하고,

하루 중 특정 시간에 발생시킨다면(ex: 오후 6시) RTC 모드를 사용한다.

RTC 모드는 사용자가 기기의 시간 설정을 변경할 경우 의도대로 이벤트가 발생하지 않을 수 있다.

 

 

 

ELAPSED_REALTIME 예시

    alarmManager.setInexactRepeating(
            AlarmManager.ELAPSED_REALTIME_WAKEUP,
            SystemClock.elapsedRealtime() + AlarmManager.INTERVAL_HALF_HOUR,
            AlarmManager.INTERVAL_HALF_HOUR,
            alarmIntent
    )

AlarmManager가 등록된 후 30분 후 부터 30분 간격으로 알람이 발생한다.

WAKEUP 버전이므로 기기가 Doze 모드인 경우에도 작동된다.

 

 

 

RTC 예시

    val calendar: Calendar = Calendar.getInstance().apply {
        timeInMillis = System.currentTimeMillis()
        set(Calendar.HOUR_OF_DAY, 16)
        set(Calendar.MINUTE, 30)
    }

    alarmManager.setRepeating(
            AlarmManager.RTC_WAKEUP,
            calendar.timeInMillis,
            1000 * 60 * 20,
            alarmIntent
    )

오후 4시 30분 부터 20분 간격으로 알람이 발생한다.

WAKEUP 버전이므로 기기가 Doze 모드인 경우에도 작동된다.

 

 

 

알람 발생시 트리거 될 인텐트

    alarmIntent = Intent(context, AlarmReceiver::class.java).let { intent ->
        PendingIntent.getBroadcast(context, 0, intent, 0)
    }

일반 Intent가 아닌 PendingIntent가 필요하다.

PendingIntent는 말그대로 보류 인텐트, 지금 당장 인텐트를 실행하는 것이 아닌 특정 시간에 인텐트를 실행시킬 수 있도록 도와주는 객체다.

자세한 내용은 PendingIntent를 다룬 포스팅을 참고하자. https://thdbs523.tistory.com/367 

 

 

 

AlarmManager 알람 등록 함수의 종류

AlarmManager의 특징으로 Doze 모드를 깨우고 알람을 발생시킬 수 있다고 했다.

하지만 Doze 모드를 깨우는 건 권장하고 있지 않기 때문에, 기본적으로 Doze 모드에는 알람의 발생을 미룬다.

Doze 모드를 깨우는 함수와 깨우지 않는 함수를 나누어서 알아보자.

 

Doze 모드를 깨우지 않음

  • set() - 일회성 알람 등록. API 버전이 올라가면서 더이상 정확한 시간을 보장하지 않는다.
  • setRepeating() - 특정 주기로 알람을 등록. 
  • setInexactRepeating() - 특정 주기로 알람을 등록. 정확한 시간을 보장하지 않는다.

Doze 모드를 깨우고 알람 발생 (일회성 알람)

  • setAndAllowWhileIdle() - 정확한 시간을 보장하지 않는다.
  • setExactAndAllowWhileIdle() - 현재 일반적으로 사용하는 함수

 

정확한 시간을 요구하는 기능이 아니라면 setInexactRepeating(), setAndAllowWhileIdle() 등의 함수를 사용하는 것을 권장하고 있다. 이러한 함수들은 시스템이 다른 앱에 알람을 보낼 때 함께 보내기 때문에 시스템 자원을 효율적으로 사용할 수 있다. (시스템이 대기상태에서 깨는 시간 최소화)

하지만 정확한 시간에 알림이 발생한다고 하는 setExactAndAllowWhileIdle(), setRepeating() 등을 실제로 구현해봤을 때 한번도 정확한 적은 없었다..

 

추가적으로 setAlarmClock()을 사용하면 정확도가 높다고 하는데, 비슷한 시간대의 모든 앱을 Doze 모드에서 깨우기 때문에 배터리 자원을 상대적으로 많이 잡아먹는다고 한다.

 

 

 

AlarmManager 알람 취소

	alarmManager.cancel(alarmIntent)

AlarmManger 인스턴스의 cancel()을 호출하여 취소할 PendingIntent를 전달한다.

 

 

 

AlarmManager 구현 예시

class AlarmController(private val context: Context) {
	// 알람을 등록하고 취소할 AlarmManager 인스턴스 가져오기
    private val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager

    fun setAlarm(requestCode: Int) {
        Log.d(TAG, "setAlarm()")

        val intent = Intent(context, AlarmReceiver::class.java) // 알람 발생 시 실행될 intent
        val alarmIntent = PendingIntent.getBroadcast(context, requestCode, intent, 0)

        val calendar = Calendar.getInstance().apply { // 오후 3시 45분에 알람 발생
            timeInMillis = System.currentTimeMillis()
            set(Calendar.HOUR_OF_DAY, 15)
            set(Calendar.MINUTE, 45)
        }

        // 10분 주기로 알람 발생
        alarmManager.setRepeating(
            AlarmManager.RTC_WAKEUP,
            calendar.timeInMillis,
            1000 * 60 * 10,
            alarmIntent
        )
    }

    fun cancelAlarm(requestCode: Int) {
        Log.d(TAG, "cancelAlarm()")

        val intent = Intent(context, AlarmReceiver::class.java)
        val alarmIntent = PendingIntent.getBroadcast(context, requestCode, intent, 0)

        alarmManager.cancel(alarmIntent) // 알람 취소
    }

    companion object {
        private val TAG = AlarmController::class.simpleName
    }
}

설명은 주석을 참고하면 된다.

 

다음에는 Doze 모드 / AlarmManager를 활용해 특정 시간에 Notification을 발생시키는 방법을 공부하고 정리해봐야겠다.


출처 : https://thdbs523.tistory.com/374

 

[안드로이드/코틀린] AlarmManager 개념 알아보고 구현하기

AlarmManager AlarmManager는 특정한 시간과 주기로 Intent를 실행하는 기능을 제공한다. 예를 들어, 정해진 시간에 사용자에게 Notification을 보내려고 할 때 AlarmManager를 활용할 수 있다. 원하는 시간에 Alar

thdbs523.tistory.com

 

'프로그래밍 > Android' 카테고리의 다른 글

[Android] SQLite 날짜 비교  (1) 2023.11.24
[Android] Calendar를 이용해 특정시간에 푸시알림 보내기  (1) 2023.11.24
[Android] 푸시알림 구현  (1) 2023.11.23
[Android] ProgressBar 구현  (1) 2023.11.22
[Android] Room  (4) 2023.11.21

댓글