fresh digitable

めんどくさかったなってことを振り返ったり振り返らなかったりするための記録

AndroidのIntent.ACTION_DATE_CHANGEDを受け取れない人へ

次のStack Overflowのやりとりが答えの全て。

stackoverflow.com

Intent.ACTION_DATE_CHANGEDはリファレンスによると日付が変わった時(つまり毎日0時0分)に飛んでくるブロードキャストインテントらしいのだが、時刻を求める処理にバグがあって、夜中ではなく正午に飛んでくることがある。

このインテントを発行しているのはAlarmManagerServiceという内部のクラス。端末起動時のインスタンスのセットアップで「次の日の0時」を計算してアラームをセットする。

問題の箇所は前述のStack Overflowの回答にもあるように、Calendarインスタンスを使って「今の時刻の時間と分と秒とミリ秒を0にして日付に1足す」ところで、時間を午前か午後の0時としてしまっているところ。このコードを注釈なしでどこが間違っているかパッとわかればおそらくJava初段くらいのウデマエと言ったところではないだろうか。僕は4級ぐらいなのでわからなかった。

public void scheduleDateChangedEvent() {
    Calendar calendar = Calendar.getInstance();
    calendar.setTimeInMillis(System.currentTimeMillis());
    calendar.set(Calendar.HOUR, 0);   // !!! 正しくは Calendar.HOUR_OF_DAY とすべき
    calendar.set(Calendar.MINUTE, 0);
    calendar.set(Calendar.SECOND, 0);
    calendar.set(Calendar.MILLISECOND, 0);
    calendar.add(Calendar.DAY_OF_MONTH, 1);

    final WorkSource workSource = null; // Let system take blame for date change events.
    setImpl(RTC, calendar.getTimeInMillis(), 0, 0, mDateChangeSender,
    AlarmManager.FLAG_STANDALONE, workSource, null, Process.myUid());
}

つまり、端末を起動したのが午前中なら正しく夜の0時にインテントが飛んでくるはずだが、端末を起動したのが午後だとインテントは正午に飛んできてしまうということである。

Issue Trackerには2009年に報告されており、それからAndroid 6.0までずっと放置されている模様。

Issue 2880 - android - Intent. ACTION_DATE_CHANGED does not fire when the date changes. - Android Open Source Project - Issue Tracker - Google Project Hosting

どうしても日付が変わった時に何かしたいときは、 Intent.ACTION_DATE_CHANGEDを受けた時に正午だったら12時間後にオリジナルなインテントを発行するアラームをセットするなどの対策が必要。


「深夜0時に何か起きててアプリが動かない」というような相談を受けていろいろ調べた時に見つけたネタ。ちなみに相談とは全然関係なかった。