알람 예약

알람 (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 권한은 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 권한 부여 요청

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

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

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

반복 알람 설정

반복 알람을 사용하면 시스템이 반복되는 일정에 따라 앱에 알림을 보낼 수 있습니다.

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

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

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

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

  • 알람의 간격. 예를 들어 하루에 한 번, 매 시간 또는 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)
}

자바

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
)

자바

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