[Android] タイマーアプリをAlarmManagerを使って作る

ある時間にアプリから通知して欲しいという場合がよくあります。目覚まし時計とかスケジュール系のアプリなど、これらの通知には時間を管理する AlarmManager 及びその関連APIを使います。
 
 
alarmmanager_1

Android Studio 3.0.1
Android 8.1.0

 



AlarmManager

 
短時間の単純なタイマーや時間計測にはAlarmManagerではなく、Handlerを使うことが推奨されています。

For normal timing operations (ticks, timeouts, etc) it is easier and much more efficient to use Handler.

Ref: AlarmManager
https://developer.android.com/reference/android/app/AlarmManager.html
AlarmManager はアプリが起動していない時にコードを実行させたい場合(バックグラウンドにいるケース)に使うということらしいです。
 
また、このサンプルコードではAlarmをBroadcastReceiver で受けているのですが、ブロードキャストの制限事項 によると

Android 8.0 を対象にしているアプリは、暗黙的なブロードキャストに対するブロードキャスト レシーバーをマニフェストで登録できなくなりました。 

明示的な登録であれば大丈夫のようです。元々の理由が暗黙的BroadcastRecieverがたくさんあると関係ないアプリも毎回呼び出しを食らってリソース、消費電力の観点からよくないと言う理由からです。

また、AlarmManagerを使うことによる消費電力が少なくないということでしょうか、代わりに JobSchduler などを使って行った方がいいようです。(完全に切り替わらないのはそれなりに大人の事情があるようですけど)
 

 

Context.ALARM_SERVICE

 
このクラスを直接インスタンス化してはいけないようで
Context.getSystemService(Context.ALARM_SERVICE) を使います

 
その後、例えば繰り返しのアラームを設定します

 
sender は PnedingIntent のインスタンスです。これは繰り返しのアラームの例ですが、
AlarmManager でのアラーム設定は

  1. set(int type, long triggerAtMillis, PendingIntent operation)
    • 単発アラーム
  2. setRepeating(int type, long triggerAtMillis, long intervalMillis, PendingIntent operation)
    • 繰り返しアラームの設定

Android 19 以降では、Alarmmanagerのポリシーが変わり以下の機能が追加されました。
 
setExact: 開始時間からの(多少正確な)アラーム設

 
setInexactRepeating: おおまかなアラームの繰り返し設定

 
setWindow: 設定したwindow内でアラームが起動する(バッテリー電力消費と精度の妥協策?)

 
これにより、Android 19 以降では set(), setRepeating() の精度は正確ではなくなりました
setRepeating() の誤差とsetExact() setWindow()
 
基本的なものはこんなところですが、これ以外にも追加のメソッドがいくつか出てきていますのでspecを確認してください。
AlarmManager | Android Developers
 
また、その他に

  1. cancel
    • 設定したアラームの取り消し
  2. setTime
    • ミリ秒での時間設定
  3. setTimeZone
    • タイムゾーンの設定

があります
 
また、4つのアラームに関する定数があります

  1. ELAPSED_REALTIME
    • スリープ時間を含んだブートアップからの経過時間
  2. ELAPSED_REALTIME_WAKEUP
    • ELAPSED_REALTIME に加えて、実機スリープ中では wake up してくれる
  3. RTC
    • 時刻
  4. RTC_WAKEUP
    • RTCに加えて実機スリープ中では wake up してくれる

 

 

PendingIntent

 
PendingIntent は作成した Intent をタイミングを見て他のアプリケーションに渡す場合に使います。

 
getBroadcastの第2引数は requestCode です。PendingIntent が1つの場合は0で大丈夫ですが複数ある時は、この requestCode を使って Receiver 側で切り分けます

Ref: PendingIntent
http://developer.android.com/reference/android/app/PendingIntent.html

 

BroadcastReceiver

 
PendingIntent からの Intent を受け取りるクラスを新しく作ります。そこでアラームを受けトーストします。
 

 

サンプルコード

 
これらの内容をふまえて実際にコードを組んでみましょう
 
WAKE_LOCK パーミッションとBroadcast の receiver を入れます。
AndroidManifest.xml

 
ボタンをタップしてアラームをセットするようにします
MainAcrivity.java

 
アラームをBroadcastReceiver で受けます
AlarmBroadcastReceiver.java

 
activity_main.xml

 

サンプル動画

 

 
アラームを設定して開始
BroadcastReceiver で受け取るという簡単な例でした
次はアラームを通知できるようにしてみます
 
 
Alarm をNotificationManager で通知する
 
References:
AlarmManager | Android Developers
BroadcastReceiver | Android Developers
PendingIntent | Android Developers