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

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

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

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

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

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

  • アラームを通じてアプリのリソース要件を最小限に抑えることができます。タイマーを使用したり、サービスを継続的に実行したりしなくても、処理のスケジュールを設定できます。

Thread

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

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

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

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

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

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

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

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

アプリが Android 12 以降をターゲットとしている場合、システムは時間枠付きの不正確なアラームの呼び出しを少なくとも 10 分遅らせることができます。このため、600000 未満の windowLengthMillis パラメータ値は 600000 に切り捨てられます。

ほぼ一定の間隔で反復アラームを配信する

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

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

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

システムは、将来の正確な時刻に正確なアラームを呼び出します。

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

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

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

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

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

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

setExact()

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

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

setExactAndAllowWhileIdle()

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

setAlarmClock()

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

システム リソースの使用量

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

可能な限り、不正確なアラームを作成することを強くおすすめします。長時間実行する処理を行うには、アラームの BroadcastReceiverから WorkManagerまたは JobSchedulerを使用してスケジュールします。デバイスが Doze モードの間に作業を行うには、 `setAndAllowWhileIdle()` を使用して不正確なアラームを作成し、 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 ブロードキャストを送信します。アプリは、次の処理を行うブロードキャスト レシーバを実装する 必要があります。

  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_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)の 2 つがあります。 実経過時間ではリファレンスとして「システムが起動してからの経過時間」を使用し、リアルタイム クロックでは UTC(ウォール クロック)時間を使用します。つまり、実経過時間はタイムゾーンやロケールの影響を受けないため、時間の経過に基づくアラームの設定に適しています(30 秒ごとにトリガーされるアラームなど)。リアルタイム クロックは、現在のロケールに依存するアラームに適しています。

どちらのタイプにも、画面がオフの場合にデバイスの CPU のスリープを解除するように指示する「wakeup」バージョンが用意されています。これにより、スケジュール設定された時間にアラームを確実にトリガーできます。この機能は、アプリが時間に依存している場合(特定の処理を制限時間内に行う必要がある場合など)に便利です。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 分後にデバイスのスリープを解除し、アラームを 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 回、同じ時間にこの処理を行います。

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 時半ちょうどにデバイスのスリープを解除してアラームをトリガーします。その後は 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_MINUTESINTERVAL_DAYなど)のいずれかを使用する必要があります。完全なリストについては、AlarmManager をご覧ください。

アラームをキャンセルする

アプリによっては、アラームをキャンセルする機能を追加することをおすすめします。 アラームをキャンセルするには、Alarm Manager で 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 モードを終了するまで延期されます。デバイスがアイドル状態でも処理を完了させる必要がある場合に使用できる方法はいくつかあります。

  • 正確なアラームを設定できます。

  • バックグラウンド処理を行うように構築された WorkManager API を使用します。処理をできるだけ早く完了させるために、システムが処理を迅速に行うように指示できます。詳しくは、 WorkManager でタスクをスケジュールするをご覧ください。

ベスト プラクティス

反復アラームを設計する際に行うあらゆる選択が、アプリによるシステム リソースの使用方法に影響を及ぼし、選択次第でシステム リソースの乱用につながることもあります。たとえば、サーバーと同期する一般的なアプリについて考えてみましょう。同期処理が時刻に基づいて行われ、アプリのすべてのインスタンスが午後 11 時に同期される場合、サーバーに対する負荷により、レイテンシが高くなる可能性があるほか、「サービス拒否攻撃」につながる恐れもあります。アラームを使用する場合は、以下のおすすめの方法に従ってください。

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

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

    • 一方、ネットワーク リクエストを含むアラームは、ランダムな時間帯にトリガーされるようにスケジュール設定します。

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

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

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

    setRepeating() の代わりに setInexactRepeating() を使用します。 setInexactRepeating() を使用すると、 Android によって複数のアプリの反復アラームが同期され、それらが同時にトリガーされます。 これにより、デバイスのスリープを解除する回数が減り、電池の消耗を抑えることができます。Android 4.4 (API レベル 19)の時点では、すべての反復アラームが不正確なアラームです。setInexactRepeating() に比べて改善されていますが、それでも、アプリのすべてのインスタンスがほぼ同時にサーバーにアクセスすると、サーバーに大きな負荷がかかる可能性があります。setRepeating()そのため、ネットワーク リクエストの場合は、前述のようにアラームにランダム性を追加します。

  • 可能であれば、時刻に基づいてアラームをトリガーすることは避けてください。

    正確なトリガー時刻に基づく反復アラームはうまく調整できません。可能であれば、 使用してください。ELAPSED_REALTIMEアラームタイプについては次のセクションで詳しく説明します。