[Android]AlarmMangerのset系メソッドの精度

Android6.0からDozeという状態が増え、それに伴いAlarmMangerでアラームをセットするメソッドも増えたようです。
たくさんありすぎて複雑。整理しました。
★Nexus5 (Android6.0)で以下のメソッドを試したざっくりな感触
上2つは、たぶんAndroid5.0とかでも同じかと思われます。

Dozeモードについては、Doze modeのメモ android6.0以上 でまとめました。

概要

  • set、setRepeating
      → 数秒遅れることが多い。
        例えば、12:00ちょうどに受け取とりたいという場合には使えなさそう。
  • setExact、setWindow
      → ほぼ、ちょうどに受け取れます。1秒以内のずれはあるかも。。。
  • setExactAndAllowWhileIdle
      → 通常の起動している場合は、setExactと同じ感じでした。
        Doze状態中は数分遅れます。
        10回ほど試したところ、3~7分とか遅れることがありました。
        最大で15分遅れるようです。
        #公式情報があったと思うけど、失念しました。
  • setAlarmClock
      → 制限がなく、スリープさせていてもだいたいちょうどに受け取れました。
        しかし、常に端末が起きている状態=電力の消費が大きいのため、一般的なアプリとして使用は向かないと思われます。
        そのため、細かくは検証していません。

機能詳細

■API Level 1 から使える

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

■API Level 19 (android 4.4) から使える
※このAPIができたことにより、API Level 1 から使えたメソッド set、setRepeatingは正確ではなくなったようです。

  • setExact(int type, long triggerAtMillis, PendingIntent operation)
      → 開始時間からの(多少正確な)アラーム設定
  • setInexactRepeating(int type, long triggerAtMillis, long intervalMillis, PendingIntent operation)
      → おおまかなアラームの繰り返し設定
  • setWindow(int type, long windowStartMillis, long windowLengthMillis, PendingIntent operation)
      → 設定したwindow内でアラームが起動する

■API Level 21 (android 5.0) から使える

  • setAlarmClock (AlarmManager.AlarmClockInfo info, PendingIntent operation)
      → 制限が全て無いメソッド、つねにバッテリーへの影響が非常に大きい。

■API Level 23 (android 6.0) から使える

  • setAndAllowWhileIdle (int type, long triggerAtMillis, PendingIntent operation)
      → Doze状態中も発火されるスケジュール
  • setExactAndAllowWhileIdle (int type, long triggerAtMillis, PendingIntent operation)
      → Doze状態中も発火されるスケジュール(多少正確な)
     #Doze状態でも使えるメソッドも、IDLEからの復帰は15minに一度だけ許されるらしい。

精度について

API Level 19までの情報ですが、以下のサイトが見やすかったです。

実装例

    AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
    long triggerAtMillis = ~~~アラームの時間~~~;
    PendingIntent pending = ~~~アラームのPendingIntent~~~;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        // android6.0以上
        am.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, triggerAtMillis, pending);
    } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
        // android4.4以上
        am.setExact(AlarmManager.RTC_WAKEUP, triggerAtMillis, pending);
    }else {
        am.set(AlarmManager.RTC_WAKEUP, triggerAtMillis, pending);
    }

コメント

  1. しげた より:

    はじめまして
    とても良い情報ありがとうございます、最大15分遅れるにはショックですね、
    正確なアラームは作れないのか?残念です
    マニュフェストとか各バージョンごとのアラームセットしましたが
    やはり古いアンドロイドの端末の方が正確でした、ひどいですね、外国はそれでも
    良いのかな?日本では乗り遅れます、貴重な情報ありがとうございました。

    • tsuji より:

      コメントありがとうございます。あと、返信が遅れ申し訳ありません。。。

      おそらく、Android6.0あたりから、省電力やセキュリティ?のためにバックグラウンドでの動作にいろいろと制限がかかってきてことによる影響ですね。
      特に海外端末だと、端末スペックが低いのも多いので、消費電力を抑える機能のニーズは高いようです。

      正確なアラームは、AlarmMangerではなく、JobSchedulerを使うのかなと思われます。(未検証ですが。。。)
      あとは、個人使用のアプリならばDozeを無効にしたりとかで回避する方法もありそうですね。

タイトルとURLをコピーしました