Android(Kotlin)AlarmManager の壁

2020/8/31

はじめに

Android で時間指定処理(一定時間経過後のローカル通知等)をやろうと思ったらまず立ち塞がるのが AlarmManager です。API Level 毎の差異が複数あって、取っ付きづらいので、ざっくり調査内容をまとめておきます。

調査

前提

本記事においては、デバイス再起動時におけるアラーム再登録は扱いません。

結論から

API Level 毎の差異を吸収してくれる AlarmManagerCompat を使えば、事足りそうです。

押さえておくべきポイント

時間指定が正確でなくなった問題

API レベル19 以降は、OS がバッテリー節約を目的に処理をまとめて実行することを優先した結果、 set() の時間指定が正確ではなくなりました。正確な時間指定がしたい場合は setExact() を使うことになります。

setAlarmClock() の存在

API レベル21で setAlarmClock() が追加されました。 バッテリー消費対策の制約を受けずに正確な時間指定はできますが、アラームアイコン表示等、UI に制約を受ける、もちろんバッテリー消費が大きくなり易い等、弊害を伴います。

Doze モードが導入された問題

Android 6.0(API レベル 23)以降で導入された省電力機能です。 同タイミングで追加された setAndAllowWhileIdle() または setExactAndAllowWhileIdle() を使用しない限り、アラームはデバイスが Doze モードを終了するまで延期されることになります。 また、上記メソッドを使用したとしても、アラーム間隔が15分以上である必要があります。

ただし、setAlarmClock() は影響を受けません。

AlarmManagerCompat 実装内容サマリー

AlarmManagerCompat.setAlarmClock()

API レベル21以上で setAlarmClock()を、19以上で setExact() を、それ以外は set() を使っていました。 そのため、前述した setAlarmClock() の弊害は受けてしまいますが、Doze モードにおいても、正確な時間でアラーム利用ができるかと思います。

API レベル21、22でも setExact() を利用するという選択肢があるとは思いますが、本メソッドは setAlarmClock() をメイン(使える限り使う)に据えているのでしょう。

AlarmManagerCompat.setAndAllowWhileIdle()

API レベル23以上で setAndAllowWhileIdle()を、それ以外は set() を使っていました。 そのため、Doze モードにおいても、アラーム間隔が15分以上であればアラーム利用ができるかと思います。

AlarmManagerCompat.setExact()

API レベル19以上で setExact() を、それ以外は set() を使っていました。 そのため、Doze モードでなければ正確な時間でアラーム利用ができるかと思います。

AlarmManagerCompat.setExactAndAllowWhileIdle()

API レベル23以上で setExactAndAllowWhileIdle()を、19以上で setExact() を、それ以外は set() を使っていました。 そのため、Doze モードにおいても、アラーム間隔が15分以上であれば正確な時間でアラーム利用ができるかと思います。

補足

setRepeating() について

API レベル19以上では時間指定が正確ではなくなりました。ドキュメントによると、正確性が必要なら前述の正確な時間指定なメソッドを使って一度だけ処理を呼び出し、そのタイミングでもう一度時間指定をすれば良い、ってことみたいです。

だから AlarmManagerCompat にも関連メソッドがないんでしょうかね。 その分実装が手間にはなりますが、仕方ないですね。