알람을 생성하기 위해 안드로이드의
AlarmManager에 대해 학습을 요구한다.
먼저AlarmManager에서 알람을 생성하는 메서드에 대해 알아보자
// AlamrManager에서 알람을 생성하기 위한 메서드 집합
set(type: Int, triggerAtMillis: Long, operation: PendingIntent)
setAlarmClock(info: AlarmManager.AlarmClockInfo, operation: PendingIntent)
setAndAllowWhileIdle(type: Int, triggerAtMillis: Long, operation: PendingIntent)
setExact(type: Int, triggerAtMillis: Long, operation: PendingIntent)
setExactAndAllowWhileIdle(type: Int, triggerAtMillis: Long, operation: PendingIntent)
setInexactRepeating(type: Int, triggerAtMillis: Long, intervalMillis: Long, operation: PendingIntent)
setRepeating(type: Int, triggerAtMillis: Long, intervalMillis: Long, operation: PendingIntent)
setWindow(type: Int, windowStartMillis: Long, windowLengthMillis: Long, operation: PendingIntent)
알람 매니저에서 다양한 알람 생성 메서드가 나온 이유는 무엇일까?
그 이유는 '배터리 효율 관리' 와 밀접한 연관이 있다.
안드로이드는 Doze-mode(유휴 상태)를 고려하여 알람을 생성하는 방식을 나누었다.
Doze-mode : Android 6.0(API 레벨 23)부터 추가된 기능으로 기기를 오랫동안 사용하지 않는 경우 앱의 백그라운드 CPU 및 네트워크 활동을 지연시켜 배터리 소모를 줄여주는 모드
이해하기 쉽게 설명하면 디바이스 전원버튼을 눌러 절전 모드 처럼 보여줄 때 Doze-mode가 실행이 된다.
set(type: Int, triggerAtMillis: Long, operation: PendingIntent)
알람을 생성하는 가장 간단한 방법이다. 그런데... Note의 첫번째 문장에서 주의할점을 보여준다.
API 19부터 이 메서드에 전달된 트리거 시간은 부정확한 것으로 처리됩니다. 알람은 이 시간 이전에는 전달되지 않지만 지연되고 나중에 전달될 수 있습니다.
맙소사.. 우리의 요구사항은 사용자가 설정한 시간에 정확한 알람이 발생되어야 하는것이다.
현재 프로젝트는 minSdk=24로 설정하여 진행하고 있기에 해당 메서드는 사용이 불가능하다고 판단된다.
setAlarmClock(info: AlarmManager.AlarmClockInfo, operation: PendingIntent)
이번 프로젝트에서 채택한 메서드이다. 채택한 이유를 설명하기전에 해당 메서드의 내용을 살펴보자.
알람이 작동할 때, 기대하는 바는 애플리케이션이 장치를 깨워 사용자에게 알람 정보를 알리는 것입니다 -- 화면을 켜고, 소리를 재생하고, 진동을 일으키는 등의 동작을 포함합니다....
시스템이 저전력 유휴(doze) 모드에 있더라도 알람이 작동할 수 있도록 허용됩니다. 시스템은 이런 알람이 다가오는 것을 볼 때, 장치가 완전히 깨어나게 되면 발생할 수 있는 배경 작업의 양을 줄이기 위해 일부 준비 작업을 할 수도 있습니다. 이는 아침 시간대에 많은 장치들이 동시에 알람을 설정하고, 그 시간에 모두 깨어나 네트워크를 갑자기 폭주시키는 배경 작업을 시작하는 상황을 피하기 위함입니다...
주의: 정확한 알람은 사용자가 직접 사용하는 기능을 위해서만 사용되어야 합니다.
정리하자면
1. 저전력 모드일 때 사용하기에 유용함
2. 알람을 발생할 때 화면을 켜고, 소리를 재생하고, 진동을 일으키는 동작을 포함 할 수 있음
3. 장치가 완전히 깨어나기 위해 시스템에서 준비 작업을 미리 진행함
4. 정확한 시간에 울리는것을 보장할 수 있음
이는 앞으로 진행될 프로젝트의 요구사항에 맞는 조건들을 가지므로 해당 메서드를 채택하였다
요구사항
- 휴대폰이 저전력 모드이거나 사용자가 임의로 시스템 시간을 변경하여도 사용자가 설정한 정확한 시간에 알람이 발생되어야 한다.
- 알람 발생시 화면이 켜지고 소리 혹은 진동을 발생시켜 알람이 발생되었다는것을 사용자에게 알린다.
- 알람 발생시 서버에 값을 요청한다.
❗ setAlarmClock이 어떻게 정확한 알람을 보장하게 되었는지 한번 살펴볼 필요가 있다. 이는 다음 포스팅에서 살펴보고 추가적으로 알람을 생성할 때의 동작에 대해서도 같이 알아보자.
setAndAllowWhileIdle(type: Int, triggerAtMillis: Long, operation: PendingIntent)
해당 메서드 설명의 중점은 다음과 같다.
이 알람은
set과 유사하지만, 이 알람은 시스템이 저전력 유휴 상태(일명 doze 모드)일 때에도 실행될 수 있습니다...
이 유형의 알람은 유휴 상태에서 장치의 전력 사용에 상당한 영향을 줄 수 있으며, 따라서 앱 스케줄링에 상당한 배터리 소모를 유발할 수 있으므로, 신중하게 사용되어야 합니다...
남용을 줄이기 위해, 특정 애플리케이션에 대해 이 알람이 발생하는 빈도에는 제한이 있습니다. 저전력 유휴 모드에서는 이 시간이 훨씬 길어질 수 있으며, 예를 들어 15분이 될 수 있습니다.
setAndAllowWhileIdle 메서드는 set 메서드와 다르게 저전력 모드일때에도 실행이 가능하다. 대신 치명적인 단점은 알람 발생에 대한 빈도를 제한한다는 내용이었다. 이로인해 알람이 정확한 시간에 울리지 못한다는 보장을 못받기 때문에 해당 메서드의 사용은 불가능하다고 판단된다.
setExact(type: Int, triggerAtMillis: Long, operation: PendingIntent)
정확한 시간을 보장하는 메서드중 하나인 setExact 메서드이다. 하지만 이 메서드에도 아쉽게 단점이 있었으니...
메서드 설명을 한번 확인해보자.
이 메서드는 set메서드와 유사하지만, 운영 체제가 배달 시간을 조정할 수 없습니다. 알람은 요청된 트리거 시간에 가능한 한 근접하게 전달됩니다...
SDK 레벨 31 이상을 대상으로 하는 앱은 이 API를 사용하기 위해 SCHEDULE_EXACT_ALARM 권한을 요청해야 합니다. 이 권한은 배터리 제한에서 면제되지 않는 한 필요합니다...
공식문서 내용에는 명확하게 'doze-mode' 일 때 알람이 제한될수 있다는 내용은 없지만 공식문서의 요약부분을 통해 유추할 수 있다.

setExactAndAllowWhileIdle 메서드를 사용하면 setExact와는 달리 'doze-mode'에서도 실행이 가능한것으로 보인다.
그래서 'doze-mode'에 정확한 시간 보장이 어려운 setExact 메서드도 불가능하다고 판단된다.
setExactAndAllowWhileIdle(type: Int, triggerAtMillis: Long, operation: PendingIntent)
'doze-mode'에서도 정확한 시간 보장이 가능한 setExactAndAllowWhileIdle메서드도 유일한 단점이 있었으니...
남용을 줄이기 위해 특정 애플리케이션에 대해 이러한 경보가 울리는 빈도에 제한이 있습니다. 정상적인 시스템 작동에서는 이러한 경보를 거의 1분마다 발송하지 않습니다(이 시점에서 대기 중인 모든 경보가 발송됩니다). 저전력 유휴 모드에서는 이 기간이 15분과 같이 상당히 길어질 수 있습니다.
해당 메서드로 연속된 여러개의 알람을 생성할 경우 (예시. 오후 3시 10분 / 오후 3시 11분 / 오후 3시 12분) 정확한 시간에 울리지 않을수도 있다(?)는 단점이었다.
setAlarmClock 메서드를 제외하고 나머지 알람 생성 메서드들 중 자율성이 높은 메서드이지만(백그라운드에 있더라도 포그라운드 서비스 시작 가능) 이것조차 정확한 시간 보장이 어렵다면 사용하기 어렵다고 판단된다.
setInexactRepeating(type: Int, triggerAtMillis: Long, intervalMillis: Long, operation: PendingIntent)
메서드 이름에서부터 보이듯 '반복 생성'이 유용한 메서드이다. 하지만 '정확한 시간 보장'을 반대되는점을 설명글 첫 문장부터 보여주고 있다.
정확한 트리거 시간 요구 사항이 없는 반복 알람을 설정하세요; 예를 들어, 매시간 반복되지만 반드시 매 시간 정각에 발생할 필요는 없는 알람입니다. API 19부터 모든 반복 알람은 부정확합니다. 이 메서드는 API 3부터 사용 가능했기 때문에, 귀하의 애플리케이션은 안전하게 이를 호출할 수 있으며, 안드로이드의 현재 및 이전 버전 모두에서 유사한 동작을 얻을 수 있습니다.
반복 알람을 생성할 수 있는 큰 장점이 있지만 시간 보장이 어려운 메서드이므로 해당 메서드 사용은 불필요하다고 판단된다.
setRepeating(type: Int, triggerAtMillis: Long, intervalMillis: Long, operation: PendingIntent)
setInexactRepeating 메서드와 마찬가지로 '반복 생성'이 가능한 메서드이다. 해당 메서드의 설명글의 Note에도 동일한 내용을 보여주고 있다.
API 19부터 모든 반복 알람은 부정확합니다. 애플리케이션이 정확한 배달 시간을 필요로 한다면, 위에서 설명한 대로 매번 다시 예약해야 하는 한 번만 실행되는 정확한 알람을 사용해야 합니다.
setRepeating 메서드 설명을 통해 '반복이 필요한 정확한 알람 생성'은 단일 알람 생성을 매번 해주어야 하는것을 확인할 수 있다.
setWindow(type: Int, windowStartMillis: Long, windowLengthMillis: Long, operation: PendingIntent)
setWindow 메서드는 다른 알람 생성 메서드와는 다르게 '알람 발생 시간 설정'을 한다는 점이다. 이는 windowStartMillis 값에 trigger time을 설정하고 windowLengthMillis에 '알람이 발생되기 까지의 시간'을 설정한다. 예를들어 windowStartMillis 값을 오전 10시로 설정하고 windowLengthMillis 값을 15분(900,000밀리초)로 설정하였을 때 오전 10시부터 오전 10시 15분 사이에 알람이 발생한다는 것이다.
이 메서드도 현재의 요구사항에 맞지 않기 때문에 사용 불가능이라고 판단된다.

'doze-mode' 관점에서 정리한 표이다. 알람 앱에서 중요한점은 언제 어디서든 정확한 시간을 보장해야 하는것이기 때문에 이로써 setAlarmClock 메서드를 채택하여 사용하기로 결정하였다.
알람 생성은 다양한 메서드들이 존재하여 '알람 기능'을 구현하려는 개발자들에게 헷갈릴 수 있을 만한 내용인 것 같다.
다음 포스팅에서는 setAlarmClock 메서드 분석과 알람 생성 동작에 대해 살펴볼 예정이다.