* fix: 프로젝트를 진행하면서 겪은 버그 해결 방법 + 발생 이유 정리
* 현재 취준생으로 풋내기 개발자가 쓰는 글입니다.
* 그러니 조언과 지적 및 훈수는 언제나 환영입니다! 댓글로 많이 달아주세요!
문제상황
매일 특정 시간에 알람이 울리도록 다음처럼 AlarmManager에 등록해두었다.
alarmManager.setRepeating(
AlarmManager.RTC_WAKEUP,
calendar.timeInMillis,
AlarmManager.INTERVAL_DAY, // 매일 특정 시간에 알람 설정
createPendingIntent(habit)
)
그런데..
- 앱이 포그라운드에서 실행 중일 때는 잘 울리다가, 백그라운드에 있을 때 안 울린다.
- 그리고 앱이 포그라운드로 다시 돌아온 순간 알람이 울린다.
문제 원인: Doze 모드
자료를 뒤적거리면서 알아낸 문제 원인은 이전에도 들어본 적 있던 Doze 모드.
Doze 모드란
- 충전기에 연결되어 있지 않을 때, 화면을 꺼두고 일정 기간 정지 상태로 두면 기기는 Doze 모드를 실행한다.
- Doze 모드에서는 시스템이 앱의 엑세스를 제한해서 배터리를 절약한다.
언제 종료되는가?
- 기기를 움직이거나, 화면을 키거나, 충전기를 연결하여 기기를 깨울 때
Doze 상태에 있을 때 제한 사항
- 네트워크 액세스 정지
- 시스템에서 wake lock 무시
- AlarmManager 알람(setExact(), setWindow() 포함)이 다음 유지보수 기간으로 연기된다.
- WI-FI 검색 실행하지 않는다.
- 동기화 어댑터 실행을 허용하지 않는다.
- JobScheduler 실행을 허용하지 않는다.
⇒ 이 문서를 확인하고, 실제로 충전기를 연결한 상태에서 실험해보니 알림이 울리더라..
혹은 충전기를 나중에 연결하니 뒤늦게 알람이 울리는 걸 발견
![](https://t1.daumcdn.net/keditor/emoticon/friends1/large/016.gif)
문제 해결: setExactAndAllowWhileIdle()
그럼 AlarmManager는 잠자기 모드일 때 전혀 실행되지 못하는가 ?!
- 그건 아니었음.. Android 23 버전부터는 AlarmManager에 새로운 메서드가 등장!
- setAndAllowWhileIdle() 및 setExactAndAllowWhileIdle()을 도입했고 이를 통해 알람이 실행되도록 설정할 수 있다고 한다.
- 두 메소드 모두 Doze 모드를 깨움
- 정확한 시간에 울려야하므로, setExactAndAllowWhileIdle() 도입
그렇게 해서 변경된 코드.
등록할 때는 setExactAndAllowWhileIdle()로 등록하고,
알람이 울리고 나면 다음 알림을 위해 registerAlarm을 한 번 더 호출해주었다.
fun registerAlarm(habit: HabitUiModel, reRegister: Boolean = false) {
// ...
alarmManager.setExactAndAllowWhileIdle(
AlarmManager.RTC_WAKEUP,
calender.timeInMillis,
createPendingIntent(habit)
)
}
class AlarmReceiver : BroadcastReceiver() {
// ...
override fun onReceive(context: Context?, intent: Intent?) {
// ...
notificationManager.showNotification(habit)
alarmHelper.registerAlarm(habit, reRegister = true)
}
}
Doze 모드 테스트
공식 문서에서는 Doze 모드 시에 테스트하는 법을 아래 명령어로 제공해주고 있다.
// doze 강제 활성화
$ adb shell dumpsys deviceidle force-idle
// doze 모드 해제
$ adb shell dumpsys deviceidle unforce
// 배터리 상태 재설정
$ adb shell dumpsys battery reset
이를 통해 Doze 모드에서도 알람이 정확한 시간에 울리는 것을 확인했다.
메모: AlarmManager가 잘 등록되어 있는지 확인하는 방법
Emulator 실행 후 터미널에서 다음을 실행해서 Alarm 등록 여부를 확인할 수 있다.
- Window OS: adb shell dumpsys alarm | findstr [패키지명]
- Mac OS: adb shell dumpsys alarm | grep [패키지명]
'Android' 카테고리의 다른 글
[TIL/개념] Hilt로 의존성 주입하기: 개념 + 겪은 이슈 정리 (6) | 2023.07.12 |
---|---|
[TIL/개념] Android Notification + PendingIntent (0) | 2023.07.11 |
[적용기] Clean Architecture는 정말 좋을까? (2) | 2023.05.13 |
[적용기] MVVM ViewModel과 AAC ViewModel (4) | 2023.05.10 |
[TIL/개념] Android의 Context와 ApplicationContext (0) | 2023.04.30 |