Я создаю приложение для отслеживания питания, в котором пользователи должны получать напоминание в определенное время (например, 15:00 и 20:00), если они не записывали никаких данных за текущий день.
Проблема: Уведомления работают отлично, пока приложение находится на переднем плане или в фоновом режиме (свернуто). Однако, как только приложение удаляется (удаляется) из списка последних приложений, AlarmManager никогда не запускает BroadcastReceiver, или приемник закрывается до того, как сможет отобразить уведомление.
Среда
- Целевой SDK: 35 (Android) 15)
- Минимальный SDK: 24
- UI Framework: Jetpack Compose
- Внедрение зависимостей: Hilt
- Тестовое устройство: Физическое устройство под управлением Android 14
- WorkManager: Сначала пробовал OneTimeWorkRequest с setInitialDelay, но результат был слишком неточным (задержка на 10–30 минут).
- AlarmManager (Exact): переключился на AlarmManager.setExactAndAllowWhileIdle, чтобы тревога сработала даже в спящем режиме.
- goAsync() в приемнике: реализован goAsync() в BroadcastReceiver, чтобы позволить области Coroutine выполнять быструю проверку (локальные SharedPreferences) перед завершением процесса.
- Локальный кеш: Вместо выполнения сетевого вызова (Supabase) в фоновом режиме я теперь сохраняю «last_tracked_date» в SharedPreferences всякий раз, когда пользователь регистрирует еду. Приемник проверяет только это локальное значение.
- Разрешения: Добавлены POST_NOTIFICATIONS, SCHEDULE_EXACT_ALARM, USE_EXACT_ALARM и RECEIVE_BOOT_COMPLETED в манифест.
- Оптимизация батареи: Оптимизация батареи отключена вручную для приложение во время тестирования.
1. Регистрация манифеста:
Код: Выделить всё
Код: Выделить всё
val intent = Intent(context, ReminderReceiver::class.java)
val pendingIntent = PendingIntent.getBroadcast(
context, requestCode, intent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
if (alarmManager.canScheduleExactAlarms()) {
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, calendar.timeInMillis, pendingIntent)
}
Код: Выделить всё
class ReminderReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val pendingResult = goAsync()
CoroutineScope(Dispatchers.IO).launch {
try {
// Check local SharedPreferences
val hasTracked = settingsManager.hasTrackedToday()
if (!hasTracked) {
showNotification(context)
}
} finally {
pendingResult.finish()
}
}
}
}
- Откройте приложение и установите напоминание на 2 минуты в будущем через пользовательский интерфейс.
- Не регистрируйте еду (поэтому напоминание должно сработать).
- Принудительно закройте приложение или проведите пальцем по нему из списка недавних задач.
- Подождите, пока пройдет время -> Результат: уведомление не появляется.
- Если приложение остается открытым, уведомление появляется точно вовремя.
Существует ли какое-либо современное ограничение Android (особенно на устройствах Samsung/Pixel), которое не позволяет AlarmManager запускать BroadcastReceiver, если пользователь вручную закрыл приложение? Поскольку это приложение связано со здоровьем, точное время имеет решающее значение. Есть ли лучшие альтернативы goAsync() для проверки в течение 1 секунды после срабатывания сигнализации?
Инструкции для пользователя:
- Скопируйте содержимое выше.
- Перейдите к переполнению стека.
- Отметьте его тегами: android, kotlin, android-alarmmanager, Broadcastreceiver, jetpack-compose.
Подробнее здесь: https://stackoverflow.com/questions/798 ... -is-swiped
Мобильная версия