アラームのスケジュールを設定する

アラーム(AlarmManager クラスに基づく)を使用すると、アプリのライフタイム外で時間ベースのオペレーションを実行できます。たとえば、アラームを使用して、1 日に 1 回サービスを開始して天気予報をダウンロードするなど、長時間実行オペレーションを開始できます。

アラームには以下の特徴があります。

  • 設定した時間または周期的(あるいはその両方)にインテントを開始できます。

  • ブロードキャスト レシーバと組み合わせて使用すると、ジョブや WorkRequest をスケジュールして他のオペレーションを実行できます。

  • これらはアプリの外部で動作するため、アプリが実行されていないときや、デバイス自体がスリープ状態のときでも、イベントやアクションをトリガーするために使用できます。

  • これらは、アプリのリソース要件を最小限に抑えるのに役立ちます。タイマーや継続的に実行されるサービスに依存することなく、オペレーションをスケジュールできます。

不正確なアラームを設定する

アプリが不正確なアラームを設定すると、システムは将来の特定の時点でアラームを配信します。不正確なアラームは、Doze などのバッテリー節約制限を考慮しながら、アラーム配信のタイミングに関する一定の保証を提供します。

デベロッパーは、次の API 保証を利用して、不正確なアラーム配信のタイミングをカスタマイズできます。

特定の時間の経過後にアラームを配信する

アプリが set()、setInexactRepeating()、または setAndAllowWhileIdle() を呼び出す場合、指定されたトリガー時間より前にアラームが鳴ることはありません。

Android 12(API レベル 31)以降では、バッテリー セーバーや Doze などのバッテリー節約制限が有効になっていない限り、システムは指定されたトリガー時間の 1 時間以内にアラームを呼び出します。

特定の時間枠内にアラームを配信する

アプリが setWindow() を呼び出すと、指定されたトリガー時間より前にアラームが鳴ることはありません。バッテリー節約の制限が有効になっていない限り、アラームは指定されたトリガー時間から指定された時間枠内に配信されます。

アプリが Android 12 以降をターゲットとしている場合、システムは時間枠付きの不正確なアラームの呼び出しを 10 分以上遅らせることができます。このため、600000 未満の windowLengthMillis パラメータ値は通常、600000 にクリップされます。特に、アラームが近い将来にトリガーされるようにスケジュールされている場合は、システムがより小さなウィンドウに対応する可能性があります。

ほぼ一定の間隔で繰り返しアラームを配信する

アプリが setInexactRepeating() を呼び出すと、システムは複数のアラームを呼び出します。

  1. 最初のアラームは、指定されたトリガー時刻から、指定された時間枠内で鳴ります。
  2. 通常、後続のアラームは、指定された時間枠が経過した後に鳴ります。アラームの連続する 2 回の呼び出しの間隔は、一定ではありません。

正確なアラームを設定する

システムは、将来の正確なタイミングで正確なアラームを呼び出します。

ほとんどのアプリは、不正確なアラームを使用してタスクやイベントのスケジュール設定を行い、いくつかの一般的なユースケースを完了できます。アプリのコア機能が正確な時刻のアラームに依存している場合(アラームアプリやカレンダー アプリなど)は、代わりに正確なアラームを使用しても問題ありません。

正確なアラームを必要としないユースケース

正確なアラームを必要としない一般的なワークフローを以下に示します。

アプリの全期間におけるタイミング オペレーションのスケジュール設定
Handler クラスには、アプリの実行中に n 秒ごとに処理を行うなど、タイミング オペレーションを処理するための優れたメソッドがいくつか含まれています。たとえば、postAtTime() や postDelayed() などです。これらの API は、リアルタイムではなくシステム稼働時間に依存します。
アプリの更新やログのアップロードなど、バックグラウンド処理のスケジュール設定
WorkManager を使用すると、タイミングが重要となる定期的な処理のスケジュールを設定できます。繰り返し間隔と flexInterval(15 分以上)を指定して、処理のランタイムを細かく定義できます。
特定の時間が経過した後に行う必要があるユーザー指定のアクション(システムがアイドル状態の場合でも)
不正確なアラームを使用します。具体的には、setAndAllowWhileIdle() を呼び出します。
特定の時間が経過した後に行う必要があるユーザー指定のアクション
不正確なアラームを使用します。具体的には、set() を呼び出します。
指定された時間枠内で行われる可能性があるユーザー指定のアクション
不正確なアラームを使用します。具体的には、setWindow() を呼び出します。アプリが Android 12 以降をターゲットとしている場合、指定できる最短の時間枠は 10 分です。

正確なアラームを設定する方法

アプリは、次のいずれかの方法を使用して正確なアラームを設定できます。これらのメソッドは、リストの下部にあるものほど、より時間的に重要なタスクを処理しますが、より多くのシステム リソースを必要とするように並べられています。

setExact()

他のバッテリー節約機能が有効になっていない限り、将来のほぼ正確な時刻にアラームを呼び出します。

アプリの処理がユーザーにとって時間的に重要でない限り、このメソッドを使用して正確なアラームを設定します。

setExactAndAllowWhileIdle()

バッテリー節約機能が有効になっている場合でも、将来のほぼ正確な時刻にアラームを呼び出します。

setAlarmClock()

将来の正確な時刻にアラームを呼び出します。これらのアラームはユーザーに明確に表示されるため、システムが配信時間を調整することはありません。システムは、これらのアラームを最も重要なアラームとして識別し、必要に応じて低電力モードを終了してアラームを配信します。

システム リソースの消費

アプリが設定した正確なアラームをシステムがトリガーすると、デバイスはバッテリー駆動時間などのリソースを大量に消費します。特に、省電力モードの場合は顕著です。さらに、システムはリソースをより効率的に使用するために、これらのリクエストを簡単にバッチ処理できません。

可能な限り、不正確なアラームを作成することを強くおすすめします。より長い処理を実行するには、アラームの BroadcastReceiver から WorkManager または JobScheduler を使用してスケジュールを設定します。デバイスが Doze モードのときに処理を実行するには、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

  • ユーザーによる許可
  • より幅広いユースケース
  • アプリは権限が取り消されていないことを確認する必要がある

Android 13(API レベル 33)以降をターゲットとするアプリを新規インストールした場合、SCHEDULE_EXACT_ALARM 権限は事前付与されません。ユーザーがバックアップと復元の処理を介して Android 14 を搭載したデバイスにアプリデータを転送する場合、新しいデバイスでは SCHEDULE_EXACT_ALARM 権限が拒否されます。ただし、この権限が既存のアプリに付与されていた場合は、デバイスが Android 14 にアップグレードされたときにこの権限が事前付与されます。

注: setExact API などで OnAlarmListener オブジェクトを使用して正確なアラームが設定されている場合、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 ブロードキャストをアプリに送信します。アプリは、次の処理を行うブロードキャスト レシーバを実装する必要があります。

  1. アプリに特別なアプリアクセスがまだあることを確認します。そのためには、canScheduleExactAlarms() を呼び出します。このチェックにより、ユーザーがアプリに権限を付与した直後に権限を取り消した場合でも、アプリを保護できます。
  2. アプリの現在の状態に基づいて、アプリに必要な正確なアラームを再スケジュールします。このロジックは、アプリが ACTION_BOOT_COMPLETED ブロードキャストを受信したときの動作と同様です。

ユーザーに SCHEDULE_EXACT_ALARM 権限の付与をリクエストする

[アラームとリマインダーの設定を許可する] というオプション
図 1. システム設定の [アラームとリマインダー] の特別なアプリアクセスのページ。ユーザーはここで、アプリが正確なアラームを設定することを許可できます。

必要に応じて、図 1 に示すように、システム設定の [アラームとリマインダー] 画面にユーザーを誘導できます。そのための手順は次のとおりです。

  1. アプリの UI で、アプリが正確なアラームのスケジュールを設定する必要がある理由をユーザーに説明します。
  2. ACTION_REQUEST_SCHEDULE_EXACT_ALARM インテント アクションを含むインテントを呼び出します。

反復アラームを設定する

繰り返しアラームを使用すると、システムは繰り返しスケジュールでアプリに通知できます。

アラームの設計が不十分だと、バッテリーを消耗し、サーバーに大きな負荷がかかる可能性があります。そのため、Android 4.4(API レベル 19)以降では、すべての繰り返しアラームが不正確なアラームになります。

反復アラームには以下の特徴があります。

  • アラームの種類。詳しくは、アラームタイプを選択するをご覧ください。

  • トリガー時間。指定したトリガー時間が過去の場合、アラームはすぐにトリガーされます。

  • アラームの間隔。たとえば、1 日 1 回、1 時間ごと、5 分ごとなどです。

  • アラームがトリガーされたときに開始するペンディング インテント。同じペンディング インテントを使用する 2 つ目のアラームを設定すると、元のアラームが置き換えられます。

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

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)の 2 種類があります。経過リアルタイムは「システム起動からの時間」を基準として使用し、リアルタイム クロックは UTC(実時間)を使用します。つまり、経過リアルタイムは、タイムゾーンや言語 / 地域の影響を受けないため、時間の経過に基づいてアラームを設定する(たとえば、30 秒ごとにアラームを起動する)のに適しています。リアルタイム クロック タイプは、現在の言語 / 地域に依存するアラームに適しています。

どちらのタイプにも「wakeup」バージョンがあり、画面がオフの場合にデバイスの CPU を復帰させます。これにより、アラームがスケジュールされた時刻に確実に鳴るようになります。これは、アプリに時間依存関係がある場合に便利です。たとえば、特定のオペレーションを実行する期間が限られている場合です。アラームタイプのウェイクアップ バージョンを使用しない場合、デバイスが次に起動したときに、すべての繰り返しアラームが起動します。

特定の間隔(30 分ごとなど)でアラームをトリガーするだけでよい場合は、経過リアルタイム タイプを使用します。一般的に、この方法が適しています。

1 日の特定の時刻にアラームを起動する必要がある場合は、時計ベースのリアルタイム クロック タイプのいずれかを選択します。ただし、このアプローチにはいくつかのデメリットがあります。アプリが他の言語 / 地域に適切に翻訳されない可能性があり、ユーザーがデバイスの時刻設定を変更すると、アプリで予期しない動作が発生する可能性があります。また、前述のように、リアルタイム クロック アラームタイプを使用すると、スケーラビリティが低下します。可能であれば、「経過リアルタイム」アラームを使用することをおすすめします。

以下に、アラームタイプの一覧を示します。

  • 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 分後にデバイスのスリープを解除し、アラームを 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 時頃にアラームを鳴らすようにデバイスを復帰させ、1 日 1 回同じ時刻に繰り返します。

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

アラームに必要な精度を決定する

前述のように、アラームタイプの選択は、アラームを作成する最初のステップとなることがよくあります。もう 1 つの区別は、アラームの精度です。ほとんどのアプリでは、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 をアプリが受信できるようになります(これは、ユーザーがアプリを少なくとも 1 回起動している場合にのみ機能します)。

    <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" に設定されています。つまり、アプリが明示的に有効にしない限り、レシーバは呼び出されません。これにより、ブート レシーバが不必要に呼び出されるのを防ぐことができます。レシーバを有効にするには(たとえば、ユーザーがアラームを設定する場合)、次のようにします。

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

デバイスが Doze モードのときにアラームを呼び出す

Android 6.0(API レベル 23)を搭載したデバイスは、デバイスのバッテリー駆動時間を延ばす Doze モードをサポートしています。デバイスが Doze モードの場合、アラームは作動しません。スケジュール設定されたアラームは、デバイスが Doze モードを終了するまで延期されます。デバイスがアイドル状態のときでも作業を完了する必要がある場合は、いくつかのオプションを利用できます。

ベスト プラクティス

繰り返しアラームを設計する際の選択はすべて、アプリがシステム リソースを使用(または乱用)する方法に影響する可能性があります。たとえば、サーバーと同期する人気のアプリがあるとします。同期オペレーションが時刻に基づいており、アプリのすべてのインスタンスが午後 11 時に同期する場合、サーバーの負荷によりレイテンシが高くなったり、「サービス拒否攻撃」が発生したりする可能性があります。アラームを使用する場合は、以下のおすすめの方法に従ってください。

  • 繰り返しアラームの結果としてトリガーされるネットワーク リクエストにランダム性(ジッター)を追加します。

    • アラームがトリガーされたときにローカル処理を実行します。「ローカル作業」とは、サーバーにアクセスしない、またはサーバーからのデータを必要としない作業を意味します。

    • 同時に、ネットワーク リクエストを含むアラームを、ランダムな期間に起動するようにスケジュールします。

  • アラームの頻度は最小限に維持します。

  • デバイスを不必要に復帰させない(この動作は、アラームタイプを選択するで説明されているように、アラームタイプによって決まります)。

  • アラームのトリガー時間を必要以上に正確に設定しないでください。

    setRepeating() ではなく setInexactRepeating() を使用します。setInexactRepeating() を使用すると、Android は複数のアプリの繰り返しアラームを同期し、同時に起動します。これにより、システムがデバイスを復帰させる回数が減り、バッテリーの消耗が軽減されます。Android 4.4(API レベル 19)以降、すべての繰り返しアラームは不正確なアラームになります。setInexactRepeating() は setRepeating() よりも改善されていますが、アプリのすべてのインスタンスがほぼ同時にサーバーにアクセスすると、サーバーに過大な負荷がかかる可能性があります。そのため、ネットワーク リクエストの場合は、前述のようにアラームにランダム性を追加します。

  • 可能であれば、アラームを時刻に基づいて設定しないようにします。

    正確なトリガー時間に基づく繰り返しアラームは、スケーラビリティに欠けます。ELAPSED_REALTIME を使用してください。さまざまなアラームタイプについては、次のセクションで詳しく説明します。