Android ACTION_DATE_CHANGED трансляция
У меня есть Nexus S, и когда я меняю дату вручную на телефоне, ACTION_DATE_CHANGED не всегда транслируется. Если я изменю дату с 13 февраля 2014 года по 14 февраля 2014 года, я не получил ACTION_DATE_CHANGED для работы, но если я буду устанавливать ее на несколько лет в будущем, я иногда ее запускаю.
Я могу (99%) уверять вас, что я не злоупотребляю IntentFilters, BroadcastReceivers и т.д. Мне просто интересно, почему эта трансляция настолько плохо документирована. Быстрое сканирование через SO и Google показывает, что люди не уверены, происходит ли это, когда пользователь вручную меняет его, или когда дата переполняется в 12:00 или каждый день, или и то, и другое. Мой опыт показывает, что это довольно противоречиво в отношении пользовательских изменений, и я не пробовал системные изменения.
Я прохожу через код AOSP и выделяю все точки, в которых это происходит, и отчитывается.
Изменить: вопрос: кто-нибудь знает, что здесь происходит?: -)
Ответы
Ответ 1
Вот код из 4.0.3_r1 в frameworks/base/services/java/android/server/AlarmManagerService.java.
Сначала мы создаем PendingIntent mDateChangeSender;
private final PendingIntent mDateChangeSender;
Затем в конструкторе AlarmManagerService.java мы настраиваем PendingIntent:
Intent intent = new Intent(Intent.ACTION_DATE_CHANGED);
intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
mDateChangeSender = PendingIntent.getBroadcast(context, 0, intent, 0);
Затем позже в конструкторе:
mClockReceiver.scheduleDateChangedEvent();
Итак, что такое mClockReceiver? Просто BroadcastReceiver прослушивает Intent.ACTION_TIME_TICK и Intent.ACTION_DATE_CHANGED. В нем onReceive():
...
else if (intent.getAction().equals(Intent.ACTION_DATE_CHANGED)) {
...
scheduleDateChangedEvent();
}
Затем, позже, мы найдем метод scheduleDateChangedEvent():
public void scheduleDateChangedEvent() {
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
calendar.add(Calendar.DAY_OF_MONTH, 1);
set(AlarmManager.RTC, calendar.getTimeInMillis(), mDateChangeSender);
}
Таким образом, он устанавливает одноразовый сигнал тревоги, начиная с текущего времени, затем устанавливая час/мин/сек/милли до нуля, затем добавляя день, поэтому, если бы сегодня было 13:30, то в следующий раз в течение 10 часов и 30 минут.
Это не означает, что здесь нет ошибок или чего-то еще, но он СМОТРЕТЬ, как ACTION_DATE_CHANGED, должен стрелять в полночь каждый день.
СЕЙЧАС - если мне нужно изменить дату на телефоне, скажем, 10 лет в будущем. Код для обработки изменения во времени запустит первое событие ACTION_DATE_CHANGED, а затем заплатит новый ACTION_DATE_CHANGED, который будет запущен, через 10 лет + часть дня. Затем, если мы изменим дату на 10 лет, до нужной даты, тревога по-прежнему планируется уволить через 10 лет, у вас не будет срабатывания ACTION_DATE_CHANGED (если вы не установите дату более 10 лет - попробуйте!).
tl; dr: Это ошибка в Android.
Ответ 2
Соответствие исследования ZachM, https://code.google.com/p/android/issues/detail?id=2880 регистрирует ошибку AOSP, где после того, как часы будут установлены назад, ACTION_DATE_CHANGED
не будет срабатывать снова, пока часы догоняют то, что будет на следующий день.
(Там также есть заметка о многочасовых задержках в этой трансляции. Последствия установки часов для тестирования или изменения даты во время сна?)
Вне ошибки ACTION_DATE_CHANGED
указывает, что часы достигли следующего дня, а ACTION_TIME_CHANGED
(== "android.intent.action.TIME_SET"
) указывает, что часы были установлены (скорректированы).
ZachM "Если бы я исправлял это..." звучит как прекрасное обходное решение, используя такой сигнал тревоги в приложении (не транслируется).
ИЗМЕНИТЬ
Ошибка AOSP # 2880 содержит новый комментарий, указывающий на ошибку (в другом?) в scheduleDateChangedEvent()
: где он вызывает calendar.set(Calendar.HOUR, 0);
, первый параметр должен быть HOUR_OF_DAY
.
Из java.util.Calendar:
ЧАС используется для 12-часового такта (0 - 11). Полдень и полночь представлены 0, а не на 12. Например, в 10: 04: 15.250 PM ЧАС составляет 10.
HOUR_OF_DAY используется для 24-часовых часов. Например, в течение 10: 04: 15,250 PM HOUR_OF_DAY составляет 22.
Итак, если scheduleDateChangedEvent()
работает во время PM дня дня, он будет планировать следующий сигнал тревоги в течение полудня, а не в полночь.
Ответ 3
Я также столкнулся с той же проблемой. Я заметил, что даже при использовании ACTION_TIME_CHANGED
и ACTION_DATE_CHANGED
вместе, я не смог обнаружить всегда, когда изменилась дата. Я думаю, что это ошибка на платформе.
Итак, я добавил приемник для ACTION_TIME_TICK
и зарегистрировал этот обратный вызов, когда дата изменилась.
Ответ 4
Фактически вы можете использовать BroadcastReceiver. Просто используйте ACTION_TIMEZONE_CHANGED тоже.
Я сделал хорошее решение для этого, здесь:
fooobar.com/info/448805/...