安卓每日7点本地通知异常:设置后凌晨12点触发求排查
问题分析与解决方案
看起来你遇到的问题核心是时区设置错误加上Calendar的24小时制与12小时制设置冲突,导致AlarmManager计算的触发时间和预期完全不符。
错误点拆解
- 你硬把Calendar的时区设为
GMT,但设备实际使用的是本地时区,这会导致你设置的6:59被解析为GMT时间,转换到本地时区后就变成了凌晨12点左右(具体偏差由你所在时区与GMT的差值决定)。 - 同时设置
Calendar.HOUR_OF_DAY(24小时制)和Calendar.AM_PM是冗余且冲突的:HOUR_OF_DAY优先级更高,AM_PM的设置会被直接忽略,这行代码完全没必要加。
修正后的代码
把MainActivity里的dailyVerseNotification方法改成下面这样:
private void dailyVerseNotification() { Calendar time = Calendar.getInstance(); // 移除硬编码的GMT时区,使用设备默认的本地时区 time.set(Calendar.HOUR_OF_DAY, 7); // 直接设置为早上7点(24小时制) time.set(Calendar.MINUTE, 0); time.set(Calendar.SECOND, 0); // 如果当前时间已经过了今天7点,就把时间顺延到明天7点,避免触发一次通知 if (time.getTimeInMillis() < System.currentTimeMillis()) { time.add(Calendar.DAY_OF_MONTH, 1); } Intent intent = new Intent(getApplicationContext(), NotificationReceiver.class); PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 100, intent, // Android 12及以上必须指定IMMUTABLE/MUTABLE,按需选择 Build.VERSION.SDK_INT >= Build.VERSION_CODES.S ? PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE : PendingIntent.FLAG_UPDATE_CURRENT); AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE); assert alarmManager != null; // 针对不同Android版本适配精准触发逻辑 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, time.getTimeInMillis(), pendingIntent); } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { alarmManager.setExact(AlarmManager.RTC_WAKEUP, time.getTimeInMillis(), pendingIntent); } else { alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, time.getTimeInMillis(), AlarmManager.INTERVAL_DAY, pendingIntent); } // 注意:Android 6.0之后setRepeating的精准度会被系统调整,如需精准每日触发,建议在NotificationReceiver中重新设置下一次闹钟 }
额外注意事项
- 权限要求:Android 12(API 31)及以上需要在Manifest中添加
SCHEDULE_EXACT_ALARM权限,部分场景还需动态申请:
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
- Doze模式适配:如果需要设备休眠时也能精准触发,
setExactAndAllowWhileIdle是更可靠的选择,但它不支持重复闹钟,需要在NotificationReceiver收到广播后,重新设置第二天的闹钟。 - PendingIntent标记:Android 12及以上强制要求PendingIntent指定
FLAG_IMMUTABLE或FLAG_MUTABLE,不需要修改Intent内容的话,用FLAG_IMMUTABLE更安全。
内容的提问来源于stack exchange,提问作者Vimal Thanikachalam
相关产品推荐
相关产品推荐

