Lork,
После борьбы с подобными проблемами у меня может быть несколько советов для вас. Я предполагаю, что вы используете свое устройство Android как своего рода удаленный «встроенный контроллер», который выполняет свои функции с минимальным взаимодействием с пользователем. Я считаю, что вы там на 95% и вам просто нужно внести небольшие архитектурные изменения. Поскольку вы не предоставили код, я просто объясню в абстрактных терминах, а не приведу примеры кода.
CommonsWare правильно, что вам нужно использовать AlarmManager, но я подозреваю, что вы уже знали это.
Сначала пара комментариев, чтобы убедиться, что все понятно.
Тревоги, созданные AlarmManager, существуют на системном уровне, то есть они могут существовать вне жизненного цикла действия и приложения, которое их создало. Если вы установили будильник, но не хотите, чтобы он выключался, если ваше приложение меняет состояние (например, после того, как оно было уничтожено), вы можете отменить его, используя alarmManager.cancel (pendingIntent) - просто создайте намерения и менеджер тревог с те же параметры и Android будут соответствовать сигнализации).
Аналогично, BroadcastReceivers регистрируются на системном уровне (по крайней мере, если они объявлены в manifest.xml) и могут существовать за пределами жизненного цикла действия и приложения, которое их создало. Опять же, если вы хотите убедиться, что BroadcastReceiver не сработает в ответ на событие, произошедшее после того, как ваше приложение изменило состояние (например, после того, как оно было уничтожено), вам необходимо явно отменить регистрацию в этом коде. Если это было зарегистрировано программно, тогда используйте context.unregisterReceiver (broadcastReceiver); если он был статически зарегистрирован в Манифесте, это не так просто - вам нужно будет извлечь получателя с помощью PackageManager и ComponentName (см .: Android - как отменить регистрацию получателя, созданного в манифесте? ) - и помните, что вам нужно будет снова включить приемник, если он вам понадобится снова.
Вы говорите, что уже настроили свой будильник. Убедитесь, что вы указали ELAPSED_REALTIME_WAKEUP или RTC_WAKUP для Типа будильника, чтобы он работал, даже когда телефон находится в «спящем» режиме.
Вы также говорите, что уже создали связанный BroadcastReceiver для обработки события тревоги. BroadcastReceiver должен выполнять минимум работы, поэтому вы должны обрабатывать любую обработку в отдельном потоке или путем запуска службы. Вы решили запустить Службу и завершить ее с помощью stopSelf () после ее завершения, чтобы она не использовала системные ресурсы. Пока все хорошо.
Это нормально, когда приложение работает, однако, поскольку вам требуется что-то, что надежно работает в течение неопределенного периода времени, вы должны убедиться, что вы управляете «исключительными» ситуациями, когда оно приостанавливается, устройство «спит», Приложение зависло / завершилось, или устройство перезагрузилось (и любые другие возможные сценарии исключений). Вот те проблемы, на которые я указал, которые вам нужно решить:
Во-первых: WakeLock гарантирован только на время действия метода onReceive () BroadcastReceiver. После его завершения устройство может вернуться в «спящий режим», даже если ваша Служба не запущена или даже не завершена, поэтому вам необходимо создать WakeLock, передать его Службе и освободить ее, прежде чем вы остановите Службу. (Примечание: для вашего приложения вам требуется PARTIAL_WAKE_LOCK). Будьте очень осторожны при использовании WakeLocks - убедитесь, что вы держите WakeLock только в течение минимально необходимого времени и освобождаете его, так как его использование может привести к чрезмерной разрядке батареи). См. http://www.netmite.com/android/mydroid/development/pdk/docs/power_management.html для примера использования WakeLocks.
Второе: если вы сбросите свою тревогу в коде (вместо определения автоматически повторяющейся), сделайте это в методе OnReceive () BroadcastReceiver или в качестве первого шага в запущенной вами службе - это обеспечит Тревога повторяется независимо от состояния приложения или устройства.
В-третьих: убедитесь, что любойИспользуемые вами контексты будут ненулевыми значениями.Вы можете динамически извлекать контекст в Сервисе, используя getApplicationContext ().В противном случае это может быть достигнуто путем ТОЧНОЙ передачи контекста из вашего приложения в сигнализацию и обеспечения его полного прохождения через BroadcastReceiver и связанные потоки и службы.Если у вас есть статически сохраненный контекст в вашем приложении, так что вы можете получить его где угодно, тогда он вернет нулевое значение, если приложение завершено.Если вы используете контекст (например, для извлечения ресурса, доступа к базе данных и т. Д.), И он имеет значение null, это вызовет исключение нулевого указателя, и Service или BroadcastReceiver потерпит крах.Я полагаю, что это наиболее вероятная причина того, что ваши приемники Broadcast не работают, когда ваше приложение завершено.
В-четвертых: вы можете делать ссылки на ResourceID (например, R.drawable.icon) в вашей службе илиBroadcastReceiver полностью определен (. R.drawable.icon) или сгенерирован из переданного контекста.Я еще не нашел, что это необходимо, но я подозреваю, что это может быть разумно.
Пятое: Реализация отдельного BroadcastReceiver для обработки сценария перезагрузки устройства (событие ON_BOOT_COMPLETE).Вы можете получить этот приемник для повторного запуска приложения, если это необходимо, или он может запустить службу, чтобы проверить, что ваше приложение должно быть активным, настроить любые необходимые параметры и настроить соответствующие сигналы тревоги, а затем завершить его с помощью stopSelf (),или просто снова установите будильник и позвольте этому приемнику справиться со всем этим.Не забудьте убедиться, что у службы есть WakeLock в течение всего срока ее действия, а также после ее завершения.Если вы не просто перезапустите приложение или Службу (объявленную как часть вашего приложения), то вам также следует статически хранить правильный контекст в качестве атрибута класса в BroadcastReceiver, если он вам нужен, чтобы он был доступен для доступа.resources.
Несколько других вещей, которые вы можете рассмотреть: поскольку ваша установка удаленная, я бы серьезно подумал о сохранении любых постоянных данных в таблицах базы данных SQLite.Это обеспечит возможность восстановления данных между завершениями приложений и перезагрузками устройства без необходимости их регенерации.Если ваше приложение взаимодействует с серверной службой, рассмотрите возможность использования push-уведомлений для инициируемой сервером связи, а не периодически проводите опрос приложения.Push-уведомления также можно использовать для «пробуждения и запуска служб и приложений», поэтому их можно использовать как часть удаленного механизма для запроса состояния устройства и вашего приложения.Этот подход также более энергоэффективен и своевременен.Публикуйте информацию в LogCat в ключевых точках вашего кода для отладки.Если приложение завершается, то adb прекращает отслеживать исходный код, выполняемый для получателя и службы, но LogCat продолжает функционировать, поэтому его можно использовать для проверки пути через код и значения переменных.
Другие люди могут иметьлучшие способы решения этих проблем или некоторые другие указания (я, конечно, был бы очень рад увидеть другие отзывы), но я надеюсь, что эти идеи полезны и удачи!