알람 예약

알람 (AlarmManager 클래스 기반)을 사용하면 애플리케이션의 전체 기간 외에 시간 기반 작업을 실행할 수 있습니다. 예를 들어 알람을 사용하여 하루에 한 번 서비스를 시작하여 일기 예보를 다운로드하는 등 장기 실행 작업을 시작할 수 있습니다.

알람에는 다음 특징이 있습니다.

  • 지정된 시간에 또는 정해진 간격으로 인텐트를 실행합니다.

  • 브로드캐스트 수신기와 함께 사용하여 작업 또는 WorkRequests를 예약하여 다른 작업을 실행할 수 있습니다.

  • 애플리케이션 외부에서 작동하므로 앱이 실행되지 않거나 기기 자체가 절전 모드인 경우에도 이벤트나 작업을 트리거하는 데 사용할 수 있습니다.

  • 앱의 리소스 요구사항을 최소화하는 데 도움이 됩니다. 타이머나 지속적으로 실행되는 서비스에 의존하지 않고 작업을 예약할 수 있습니다.

부정확한 알람 설정

앱이 부정확한 알람을 설정하면 시스템은 향후 특정 시점에 알람을 전송합니다. 부정확한 알람은 잠자기와 같은 배터리 절약 제한을 준수하면서 알람 전송 시점에 관한 몇 가지 보장을 제공합니다.

개발자는 다음 API 보장을 활용하여 부정확한 알람 전송 시점을 맞춤설정할 수 있습니다.

특정 시간 후에 알람 전송

앱에서 set(), setInexactRepeating() 또는 setAndAllowWhileIdle()를 호출하면 제공된 트리거 시간 전에 알람이 울리지 않습니다.

Android 12 (API 수준 31) 이상에서는 절전 모드 또는 잠자기와 같은 배터리 절약 제한이 적용되지 않는 한 시스템이 제공된 트리거 시간으로부터 1시간 이내에 알람을 호출합니다.

특정 기간에 알람 전송

앱이 setWindow()를 호출하면 제공된 트리거 시간 전에 알람이 울리지 않습니다. 배터리 절약 제한사항이 적용되지 않는 한 알람은 지정된 트리거 시간부터 지정된 기간 내에 전송됩니다.

앱이 Android 12 이상을 타겟팅하는 경우 시스템은 시간 범위가 지정된 부정확한 알람의 호출을 최소 10분 지연할 수 있습니다. 따라서 600000 미만의 windowLengthMillis 파라미터 값은 일반적으로 600000로 잘립니다. 특히 알람이 가까운 미래에 트리거되도록 예약된 경우 시스템은 더 작은 기간을 수용할 수 있습니다.

대략 일정한 간격으로 반복 알람 전송

앱이 setInexactRepeating()를 호출하면 시스템은 여러 알람을 호출합니다.

  1. 첫 번째 알람은 지정된 트리거 시간부터 지정된 시간 내에 울립니다.
  2. 후속 알람은 일반적으로 지정된 시간 범위가 경과한 후에 울립니다. 알람이 연속으로 두 번 호출되는 사이의 시간은 달라질 수 있습니다.

정확한 알람 설정

시스템은 향후 정확한 순간에 정확한 알람을 호출합니다.

대부분의 앱은 부정확한 알람을 사용하여 작업과 이벤트를 예약함으로써 몇 가지 일반적인 사용 사례를 완료할 수 있습니다. 앱의 핵심 기능이 정확한 시간에 울리는 알람(예: 알람 시계 앱 또는 캘린더 앱)에 의존하는 경우 정확한 알람을 대신 사용해도 됩니다.

정확한 알람이 필요하지 않을 수 있는 사용 사례

다음 목록은 정확한 알람이 필요하지 않을 수 있는 일반적인 워크플로를 보여줍니다.

앱의 전체 기간 동안 타이밍 작업 예약
Handler 클래스에는 앱이 활성 상태인 동안 n초마다 일부 작업을 실행하는 등 타이밍 작업을 처리하는 데 유용한 여러 메서드가 포함되어 있습니다. postAtTime() 및 postDelayed(). 이러한 API는 실시간이 아닌 시스템 업타임을 사용합니다.
예약된 백그라운드 작업(예: 앱 업데이트 및 로그 업로드)
WorkManager는 시간에 민감한 주기적 작업을 예약하는 방법을 제공합니다. 반복 간격과 flexInterval (최소 15분)을 제공하여 작업의 세분화된 런타임을 정의할 수 있습니다.
특정 시간 후에 발생해야 하는 사용자 지정 작업 (시스템이 유휴 상태인 경우에도 해당)
부정확한 알람을 사용합니다. 구체적으로 setAndAllowWhileIdle()를 호출합니다.
특정 시간 후에 발생해야 하는 사용자 지정 작업
부정확한 알람을 사용합니다. 구체적으로 set()를 호출합니다.
지정된 시간 내에 발생할 수 있는 사용자 지정 작업
부정확한 알람을 사용합니다. 구체적으로 setWindow()를 호출합니다. 앱이 Android 12 이상을 타겟팅하는 경우 허용되는 최소 시간은 10분입니다.

정확한 알람을 설정하는 방법

앱은 다음 방법 중 하나를 사용하여 정확한 알람을 설정할 수 있습니다. 이러한 메서드는 목록 하단에 가까울수록 시간에 민감한 작업을 더 많이 처리하지만 더 많은 시스템 리소스를 요구하도록 정렬됩니다.

setExact()

다른 배터리 절약 조치가 적용되지 않는 한, 향후 거의 정확한 시간에 알람을 호출합니다.

앱의 작업이 사용자에게 시간에 민감하지 않은 경우 이 메서드를 사용하여 정확한 알람을 설정합니다.

setExactAndAllowWhileIdle()

배터리 절약 조치가 적용 중인 경우에도 향후 거의 정확한 시간에 알람을 호출합니다.

setAlarmClock()

미래의 정확한 시간에 알람을 호출합니다. 이러한 알람은 사용자에게 잘 표시되므로 시스템은 전송 시간을 조정하지 않습니다. 시스템은 이러한 알람을 가장 중요한 알람으로 식별하고 필요한 경우 저전력 모드를 종료하여 알람을 전송합니다.

시스템 리소스 소비

시스템이 앱에서 설정한 정확한 알람을 트리거하면 기기는 특히 절전 모드에 있는 경우 배터리 수명과 같은 많은 리소스를 소모합니다. 또한 시스템은 리소스를 더 효율적으로 사용하기 위해 이러한 요청을 쉽게 일괄 처리할 수 없습니다.

가능하면 부정확한 알람을 만드는 것이 좋습니다. 더 긴 작업을 실행하려면 알람의 BroadcastReceiver에서 WorkManager 또는 JobScheduler을 사용하여 예약합니다. 기기가 잠자기 모드일 때 작업을 실행하려면 setAndAllowWhileIdle()를 사용하여 부정확한 알람을 만들고 알람에서 작업을 시작합니다.

적절한 정확한 알람 권한 선언

앱이 Android 12 이상을 타겟팅하는 경우 '알람 및 리마인더' 특별 앱 액세스 권한을 얻어야 합니다. 이렇게 하려면 다음 코드 스니펫과 같이 앱의 매니페스트 파일에서 SCHEDULE_EXACT_ALARM 권한을 선언합니다.

<manifest ...>
    <uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM"/>
    <application ...>
        ...
    </application>
</manifest>

앱이 Android 13 (API 수준 33) 이상을 타겟팅하는 경우 SCHEDULE_EXACT_ALARM 또는 USE_EXACT_ALARM 권한을 선언할 수 있습니다.

<manifest ...>
    <uses-permission android:name="android.permission.USE_EXACT_ALARM"/>
    <application ...>
        ...
    </application>
</manifest>

SCHEDULE_EXACT_ALARM 및 USE_EXACT_ALARM 권한은 모두 동일한 기능을 나타내지만 부여되는 방식이 다르며 지원하는 사용 사례도 다릅니다. 앱의 사용자 대상 기능에 정확한 타이밍이 필요한 경우에만 앱에서 정확한 알람을 사용하고 SCHEDULE_EXACT_ALARM 또는 USE_EXACT_ALARM 권한을 선언해야 합니다.

USE_EXACT_ALARM

SCHEDULE_EXACT_ALARM

  • 사용자가 부여함
  • 더 광범위한 사용 사례
  • 앱은 권한이 취소되지 않았는지 확인해야 합니다.

SCHEDULE_EXACT_ALARM 권한은 Android 13 (API 수준 33) 이상을 타겟팅하는 앱을 새로 설치할 때 사전 부여되지 않습니다. 사용자가 백업 및 복원 작업을 통해 Android 14를 실행하는 기기로 앱 데이터를 전송하는 경우 새 기기에서 SCHEDULE_EXACT_ALARM 권한이 거부됩니다. 그러나 기존 앱에 이미 이 권한이 있는 경우 기기가 Android 14로 업그레이드될 때 이 권한이 미리 부여됩니다.

참고: 정확한 알람이 OnAlarmListener 객체(예: setExact API에서)를 사용하도록 설정되어 있는 경우 SCHEDULE_EXACT_ALARM 권한은 필요하지 않습니다.

SCHEDULE_EXACT_ALARM 권한 사용

USE_EXACT_ALARM와 달리 SCHEDULE_EXACT_ALARM 권한은 사용자가 부여해야 합니다. 사용자와 시스템 모두 SCHEDULE_EXACT_ALARM 권한을 취소할 수 있습니다.

앱에 권한이 부여되었는지 확인하려면 정확한 알람을 설정하기 전에 canScheduleExactAlarms()를 호출합니다. 앱에서 SCHEDULE_EXACT_ALARM 권한이 취소되면 앱이 중지되고 향후 모든 정확한 알람이 취소됩니다. 즉, canScheduleExactAlarms()에서 반환하는 값은 앱의 전체 수명 주기 동안 유효합니다.

앱에 SCHEDULE_EXACT_ALARMS 권한이 부여되면 시스템은 앱에 ACTION_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED 브로드캐스트를 전송합니다. 앱은 다음을 실행하는 broadcast receiver를 구현해야 합니다.

  1. 앱에 여전히 특별한 앱 액세스 권한이 있는지 확인합니다. canScheduleExactAlarms()를 호출하면 됩니다. 이 검사는 사용자가 앱에 권한을 부여한 후 거의 즉시 취소하는 경우로부터 앱을 보호합니다.
  2. 현재 상태를 기반으로 앱에 필요한 정확한 알람을 다시 예약합니다. 이 로직은 앱이 ACTION_BOOT_COMPLETED 브로드캐스트를 수신할 때 실행하는 작업과 비슷합니다.

사용자에게 SCHEDULE_EXACT_ALARM 권한 부여 요청

'알람 및 리마인더 설정 허용' 옵션
그림 1. 사용자가 앱이 정확한 알람을 설정하도록 허용할 수 있는 시스템 설정의 '알람 및 리마인더' 특수 앱 액세스 권한 페이지

필요한 경우 그림 1과 같이 사용자를 시스템 설정의 Alarms & reminders 화면으로 보낼 수 있습니다. 그러려면 다음 단계를 완료하세요.

  1. 앱의 UI에서 사용자에게 앱이 정확한 알람을 예약해야 하는 이유를 설명합니다.
  2. ACTION_REQUEST_SCHEDULE_EXACT_ALARM 인텐트 작업이 포함된 인텐트를 호출합니다.

반복 알람 설정

반복 알람을 사용하면 시스템에서 반복 일정에 따라 앱에 알릴 수 있습니다.

잘못 설계된 알람은 배터리를 소모하고 서버에 상당한 부하를 줄 수 있습니다. 따라서 Android 4.4 (API 수준 19) 이상에서는 모든 반복 알람이 부정확한 알람입니다.

반복 알람은 다음과 같은 특성을 갖습니다.

  • 알람 유형입니다. 자세한 내용은 알람 유형 선택을 참조하세요.

  • 트리거 시간. 지정한 트리거 시간이 과거인 경우 알람이 즉시 트리거됩니다.

  • 알람의 간격. 예를 들어 하루에 한 번, 매시간 또는 5분마다 실행할 수 있습니다.

  • 알람이 트리거되면 실행되는 대기 중인 인텐트. 동일한 대기 중 인텐트를 사용하는 두 번째 알람을 설정하면 원래 알람이 대체됩니다.

PendingIntent()를 취소하려면 FLAG_NO_CREATE를 PendingIntent.getService()에 전달하여 인텐트의 인스턴스 (있는 경우)를 가져온 다음 이 인텐트를 AlarmManager.cancel()에 전달합니다.

Kotlin

val alarmManager =
    context.getSystemService(Context.ALARM_SERVICE) as? AlarmManager
val pendingIntent =
    PendingIntent.getService(context, requestId, intent,
                                PendingIntent.FLAG_NO_CREATE)
if (pendingIntent != null && alarmManager != null) {
  alarmManager.cancel(pendingIntent)
}

자바

AlarmManager alarmManager =
    (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
PendingIntent pendingIntent =
    PendingIntent.getService(context, requestId, intent,
                                PendingIntent.FLAG_NO_CREATE);
if (pendingIntent != null && alarmManager != null) {
  alarmManager.cancel(pendingIntent);
}

알람 유형 선택

반복 알람을 사용할 때 가장 먼저 고려해야 할 사항 중 하나는 알람의 유형입니다.

알람에는 '경과된 실시간'과 '실시간 시계' (RTC)라는 두 가지 일반적인 시계 유형이 있습니다. 경과된 실시간은 '시스템 부팅 이후 시간'을 참조로 사용하고 실시간 시계는 UTC (실제 시간) 시간을 사용합니다. 즉, 경과된 실시간은 시간대나 언어의 영향을 받지 않으므로 시간 경과에 따라 알람을 설정하는 데 적합합니다 (예: 30초마다 울리는 알람). 실시간 시계 유형은 현재 언어에 종속된 알람에 더 적합합니다.

두 유형 모두 'wakeup' 버전이 있으며, 이는 화면이 꺼져 있는 경우 기기의 CPU를 절전 모드 해제하도록 지시합니다. 이렇게 하면 알람이 예약된 시간에 실행됩니다. 이는 앱에 시간 종속 항목이 있는 경우에 유용합니다. 예를 들어 특정 작업을 실행할 수 있는 기간이 제한되어 있는 경우입니다. 알람 유형의 wakeup 버전을 사용하지 않으면 기기가 다음에 절전 모드에서 해제될 때 모든 반복 알람이 실행됩니다.

특정 간격 (예: 30분마다)으로 알람을 실행해야 하는 경우 경과된 실시간 유형 중 하나를 사용합니다. 일반적으로 이 방법이 더 좋습니다.

하루 중 특정 시간에 알람을 실행해야 하는 경우 시계 기반 실시간 시계 유형 중 하나를 선택합니다. 하지만 이 접근 방식에는 몇 가지 단점이 있을 수 있습니다. 앱이 다른 언어로 잘 번역되지 않을 수 있으며 사용자가 기기의 시간 설정을 변경하면 앱에서 예기치 않은 동작이 발생할 수 있습니다. 실시간 시계 알람 유형을 사용하는 것도 위에서 설명한 것처럼 확장성이 좋지 않습니다. 가능하면 '실제 경과 시간' 알람을 사용하는 것이 좋습니다.

다음은 유형 목록입니다.

  • ELAPSED_REALTIME: 기기가 부팅된 후 경과한 시간을 기준으로 대기 중인 인텐트를 실행하지만 기기를 절전 모드 해제하지는 않습니다. 경과 시간은 기기가 절전 모드였던 시간을 포함합니다.

  • ELAPSED_REALTIME_WAKEUP: 기기 부팅 후 지정된 시간이 경과하면 기기를 절전 모드에서 해제하고 대기 중인 인텐트를 실행합니다.

  • RTC: 지정된 시간에 대기 중인 인텐트를 실행하지만 기기를 절전 모드 해제하지는 않습니다.

  • RTC_WAKEUP: 지정된 시간에 대기 중인 인텐트를 실행하도록 기기를 절전 모드 해제합니다.

실제 경과 시간 알람의 예

다음은 ELAPSED_REALTIME_WAKEUP 사용의 몇 가지 예시입니다.

30분 후에 알람을 실행하고 이후 30분마다 알람을 실행하도록 기기를 절전 모드 해제합니다.

Kotlin

// Hopefully your alarm will have a lower frequency than this!
alarmMgr?.setInexactRepeating(
        AlarmManager.ELAPSED_REALTIME_WAKEUP,
        SystemClock.elapsedRealtime() + AlarmManager.INTERVAL_HALF_HOUR,
        AlarmManager.INTERVAL_HALF_HOUR,
        alarmIntent
)

자바

// Hopefully your alarm will have a lower frequency than this!
alarmMgr.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
        SystemClock.elapsedRealtime() + AlarmManager.INTERVAL_HALF_HOUR,
        AlarmManager.INTERVAL_HALF_HOUR, alarmIntent);

다음과 같이 1분 후에 기기의 절전 모드를 해제하여 일회성 알람(반복 없음)을 실행합니다.

Kotlin

private var alarmMgr: AlarmManager? = null
private lateinit var alarmIntent: PendingIntent
...
alarmMgr = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
alarmIntent = Intent(context, AlarmReceiver::class.java).let { intent ->
    PendingIntent.getBroadcast(context, 0, intent, 0)
}

alarmMgr?.set(
        AlarmManager.ELAPSED_REALTIME_WAKEUP,
        SystemClock.elapsedRealtime() + 60 * 1000,
        alarmIntent
)

자바

private AlarmManager alarmMgr;
private PendingIntent alarmIntent;
...
alarmMgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, AlarmReceiver.class);
alarmIntent = PendingIntent.getBroadcast(context, 0, intent, 0);

alarmMgr.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
        SystemClock.elapsedRealtime() +
        60 * 1000, alarmIntent);

실시간 시계 알람의 예

다음은 RTC_WAKEUP 사용의 몇 가지 예시입니다.

오후 2시경에 알람을 실행하도록 기기를 절전 모드 해제하고 하루에 한 번 같은 시간에 반복합니다.

Kotlin

// Set the alarm to start at approximately 2:00 p.m.
val calendar: Calendar = Calendar.getInstance().apply {
    timeInMillis = System.currentTimeMillis()
    set(Calendar.HOUR_OF_DAY, 14)
}

// With setInexactRepeating(), you have to use one of the AlarmManager interval
// constants--in this case, AlarmManager.INTERVAL_DAY.
alarmMgr?.setInexactRepeating(
        AlarmManager.RTC_WAKEUP,
        calendar.timeInMillis,
        AlarmManager.INTERVAL_DAY,
        alarmIntent
)

자바

// Set the alarm to start at approximately 2:00 p.m.
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, 14);

// With setInexactRepeating(), you have to use one of the AlarmManager interval
// constants--in this case, AlarmManager.INTERVAL_DAY.
alarmMgr.setInexactRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
        AlarmManager.INTERVAL_DAY, alarmIntent);

정확히 오전 8시 30분에 알람을 실행하고 이후 20분마다 기기를 절전 모드 해제합니다.

Kotlin

private var alarmMgr: AlarmManager? = null
private lateinit var alarmIntent: PendingIntent
...
alarmMgr = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
alarmIntent = Intent(context, AlarmReceiver::class.java).let { intent ->
    PendingIntent.getBroadcast(context, 0, intent, 0)
}

// Set the alarm to start at 8:30 a.m.
val calendar: Calendar = Calendar.getInstance().apply {
    timeInMillis = System.currentTimeMillis()
    set(Calendar.HOUR_OF_DAY, 8)
    set(Calendar.MINUTE, 30)
}

// setRepeating() lets you specify a precise custom interval--in this case,
// 20 minutes.
alarmMgr?.setRepeating(
        AlarmManager.RTC_WAKEUP,
        calendar.timeInMillis,
        1000 * 60 * 20,
        alarmIntent
)

자바

private AlarmManager alarmMgr;
private PendingIntent alarmIntent;
...
alarmMgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, AlarmReceiver.class);
alarmIntent = PendingIntent.getBroadcast(context, 0, intent, 0);

// Set the alarm to start at 8:30 a.m.
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, 8);
calendar.set(Calendar.MINUTE, 30);

// setRepeating() lets you specify a precise custom interval--in this case,
// 20 minutes.
alarmMgr.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
        1000 * 60 * 20, alarmIntent);

알람이 얼마나 정확해야 하는지 결정

앞서 설명한 것처럼 알람 유형을 선택하는 것은 알람을 만드는 첫 번째 단계인 경우가 많습니다. 또 다른 차이점은 알람이 얼마나 정확해야 하는지입니다. 대부분의 앱에는 setInexactRepeating()가 적합합니다. 이 메서드를 사용하면 Android는 여러 개의 부정확한 반복 알람을 동기화하고 동시에 실행합니다. 이렇게 하면 배터리 소모를 줄일 수 있습니다.

가능하면 정확한 알람을 사용하지 마세요. 하지만 엄격한 시간 요구사항이 있는 드문 앱의 경우 setRepeating()를 호출하여 정확한 알람을 설정할 수 있습니다.

setInexactRepeating()를 사용하면 setRepeating()를 사용할 때와 같은 방식으로 커스텀 간격을 지정할 수 없습니다. INTERVAL_FIFTEEN_MINUTES, INTERVAL_DAY 등 간격 상수 중 하나를 사용해야 합니다. 전체 목록은 AlarmManager를 참조하세요.

알람 취소

앱에 따라 알람을 취소하는 기능을 포함할 수도 있습니다. 알람을 취소하려면 알람 관리자에서 cancel()를 호출하여 더 이상 실행하지 않으려는 PendingIntent를 전달합니다. 예를 들면 다음과 같습니다.

Kotlin

// If the alarm has been set, cancel it.
alarmMgr?.cancel(alarmIntent)

자바

// If the alarm has been set, cancel it.
if (alarmMgr!= null) {
    alarmMgr.cancel(alarmIntent);
}

기기가 다시 시작되면 알람 시작

기본적으로 기기를 종료하면 모든 알람이 취소됩니다. 이를 방지하려면 사용자가 기기를 재부팅할 때 반복 알람을 자동으로 다시 시작하도록 애플리케이션을 설계하면 됩니다. 이렇게 하면 사용자가 알람을 수동으로 다시 시작할 필요 없이 AlarmManager가 계속 작업을 실행합니다.

다음 단계를 따르세요.

  1. 애플리케이션의 매니페스트에서 RECEIVE_BOOT_COMPLETED 권한을 설정합니다. 이렇게 하면 앱이 시스템 부팅이 완료된 후 브로드캐스트되는 ACTION_BOOT_COMPLETED를 수신할 수 있습니다 (사용자가 이미 앱을 한 번 이상 실행한 경우에만 작동함).

    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
  2. BroadcastReceiver를 구현하여 브로드캐스트를 수신합니다.

    Kotlin

    class SampleBootReceiver : BroadcastReceiver() {
    
        override fun onReceive(context: Context, intent: Intent) {
            if (intent.action == "android.intent.action.BOOT_COMPLETED") {
                // Set the alarm here.
            }
        }
    }

    자바

    public class SampleBootReceiver extends BroadcastReceiver {
    
        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent.getAction().equals("android.intent.action.BOOT_COMPLETED")) {
                // Set the alarm here.
            }
        }
    }
  3. ACTION_BOOT_COMPLETED 작업을 필터링하는 인텐트 필터를 사용하여 앱의 매니페스트 파일에 수신자를 추가합니다.

    <receiver android:name=".SampleBootReceiver"
            android:enabled="false">
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED"></action>
        </intent-filter>
    </receiver>

    매니페스트에서 부팅 수신기가 android:enabled="false"로 설정되어 있습니다. 즉, 애플리케이션에서 명시적으로 사용 설정하지 않는 한 수신자가 호출되지 않습니다. 이렇게 하면 부팅 수신기가 불필요하게 호출되는 것을 방지할 수 있습니다. 다음과 같이 수신자를 사용 설정할 수 있습니다(예: 사용자가 알람을 설정하는 경우).

    Kotlin

    val receiver = ComponentName(context, SampleBootReceiver::class.java)
    
    context.packageManager.setComponentEnabledSetting(
            receiver,
            PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
            PackageManager.DONT_KILL_APP
    )

    자바

    ComponentName receiver = new ComponentName(context, SampleBootReceiver.class);
    PackageManager pm = context.getPackageManager();
    
    pm.setComponentEnabledSetting(receiver,
            PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
            PackageManager.DONT_KILL_APP);

    이 방법으로 수신기를 사용 설정하면 사용자가 기기를 재부팅하더라도 수신기가 사용 설정된 상태로 유지됩니다. 즉, 프로그래매틱 방식으로 수신기를 사용 설정하면 재부팅 시에도 매니페스트 설정이 재정의됩니다. 수신기는 앱에서 사용 중지할 때까지 사용 설정된 상태로 유지됩니다. 다음과 같이 수신기를 사용 중지할 수 있습니다 (예: 사용자가 알람을 취소하는 경우).

    Kotlin

    val receiver = ComponentName(context, SampleBootReceiver::class.java)
    
    context.packageManager.setComponentEnabledSetting(
            receiver,
            PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
            PackageManager.DONT_KILL_APP
    )

    자바

    ComponentName receiver = new ComponentName(context, SampleBootReceiver.class);
    PackageManager pm = context.getPackageManager();
    
    pm.setComponentEnabledSetting(receiver,
            PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
            PackageManager.DONT_KILL_APP);

기기가 잠자기 모드일 때 알람 호출

Android 6.0 (API 수준 23)을 실행하는 기기는 기기 배터리 수명을 연장하는 데 도움이 되는 잠자기 모드를 지원합니다. 기기가 잠자기 모드일 때는 알람이 실행되지 않습니다. 예약된 알람은 기기가 잠자기 모드를 종료할 때까지 지연됩니다. 기기가 유휴 상태일 때도 작업을 완료해야 하는 경우 다음과 같은 몇 가지 옵션을 사용할 수 있습니다.

  • 정확한 알람을 설정합니다.

  • 백그라운드 작업을 실행하도록 빌드된 WorkManager API를 사용합니다. 작업이 최대한 빨리 완료되도록 시스템에서 작업을 신속하게 처리해야 한다고 표시할 수 있습니다. 자세한 내용은 WorkManager로 작업 예약을 참고하세요.

권장사항

반복 알람을 설계할 때 선택하는 모든 사항은 앱이 시스템 리소스를 사용하는 (또는 남용하는) 방식에 영향을 미칠 수 있습니다. 예를 들어 서버와 동기화하는 인기 앱이 있다고 가정해 보겠습니다. 동기화 작업이 시계 시간을 기반으로 하고 앱의 모든 인스턴스가 오후 11시에 동기화되는 경우 서버의 부하로 인해 지연 시간이 길어지거나 '서비스 거부'가 발생할 수도 있습니다. 알람 사용에 대한 권장사항은 다음과 같습니다.

  • 반복 알람의 결과로 트리거되는 네트워크 요청에 무작위성 (지터)을 추가합니다.

    • 알람이 트리거될 때 로컬 작업을 수행합니다. '로컬 작업'은 서버에 도달하지 않거나 서버의 데이터를 필요로 하지 않는 모든 작업을 의미합니다.

    • 동시에 네트워크 요청이 포함된 알람이 임의의 기간에 실행되도록 예약합니다.

  • 알람 빈도를 최소한으로 유지합니다.

  • 불필요하게 기기를 절전 모드에서 해제하지 않습니다. 이 동작은 알람 유형 선택에 설명된 대로 알람 유형에 따라 결정됩니다.

  • 알람의 트리거 시간을 필요 이상으로 정확하게 설정하지 마세요.

    setRepeating() 대신 setInexactRepeating()을 사용합니다. setInexactRepeating()를 사용하면 Android는 여러 앱의 반복 알람을 동기화하고 동시에 실행합니다. 이렇게 하면 시스템이 기기를 절전 모드에서 해제해야 하는 총 횟수가 줄어들어 배터리 소모가 줄어듭니다. Android 4.4(API 수준 19)부터 모든 반복 알람은 부정확한 알람입니다. setInexactRepeating()는 setRepeating()보다 개선되었지만, 앱의 모든 인스턴스가 거의 동시에 서버에 도달하면 여전히 서버에 과부하가 발생할 수 있습니다. 따라서 네트워크 요청의 경우 앞서 설명한 대로 알람에 무작위성을 추가하세요.

  • 가능하면 시계 시간을 기준으로 알람을 설정하지 마세요.

    정확한 트리거 시간을 기준으로 하는 반복 알람은 확장되지 않습니다. ELAPSED_REALTIME를 사용할 수 있으면 사용합니다. 다양한 알람 유형은 다음 섹션에서 자세히 설명합니다.