Bibbidi Bobbidi Boo
article thumbnail
Published 2023. 7. 27. 16:04
[fix] AlarmManager와 Doze 모드 Android

* 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 실행을 허용하지 않는다.

⇒ 이 문서를 확인하고, 실제로 충전기를 연결한 상태에서 실험해보니 알림이 울리더라..

혹은 충전기를 나중에 연결하니 뒤늦게 알람이 울리는 걸 발견

 

문제 해결: 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 [패키지명]


 

profile

Bibbidi Bobbidi Boo

@비비디

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!