알람 예약

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

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

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

  • broadcast receiver와 함께 이를 사용하여 작업 또는 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_ALARMUSE_EXACT_ALARM 권한은 모두 동일한 기능을 나타내지만 다르게 부여되며 서로 다른 사용 사례를 지원합니다. 앱의 사용자 대상 함수에 시간이 정확히 지정된 작업이 필요한 경우에만 앱은 정확한 알람을 사용하고 SCHEDULE_EXACT_ALARM 또는 USE_EXACT_ALARM 권한을 선언해야 합니다.

USE_EXACT_ALARM

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 권한을 부여하도록 요청

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

필요한 경우 그림 1과 같이 시스템 설정의 알람 및 리마인더 화면으로 사용자를 안내할 수 있습니다. 그러려면 다음 단계를 완료하세요.

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

반복 알람 설정

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

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

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

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

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

  • 알람의 간격. 예를 들어 하루에 한 번, 1시간마다, 5분마다

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

PendingIntent()를 취소하려면 FLAG_NO_CREATEPendingIntent.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)
}

Java

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초마다 실행되는 알람)을 설정하는 데 적합합니다. 실시간 시계 유형은 현재 언어에 따라 달라지는 알람에 더 적합합니다.

두 가지 유형 모두 화면이 꺼져 있을 때 기기의 CPU를 깨우도록 지시하는 'wakeup' 버전이 있습니다. 이렇게 하면 예약된 시간에 알람이 실행됩니다. 이는 앱에 시간 종속 항목이 있는 경우 유용합니다. 특정 작업을 실행하기 위해 제한된 윈도우가 있는 경우를 예로 들 수 있습니다. 알람 유형의 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
)

Java

// 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
)

Java

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
)

Java

// 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
)

Java

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)

Java

// 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.
            }
        }
    }
    

    Java

    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"로 설정되어 있습니다. 즉, 애플리케이션이 명시적으로 사용 설정하지 않으면 broadcast receiver가 호출되지 않습니다. 이렇게 하면 부팅 수신기가 불필요하게 호출되는 것을 방지할 수 있습니다. 다음과 같이 수신기를 사용 설정할 수 있습니다(예: 사용자가 알람을 설정한 경우).

    Kotlin

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

    Java

    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
    )
    

    Java

    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를 사용합니다. 다양한 알람 유형은 다음 섹션에서 더 자세히 설명합니다.