为什么使用AlarmManager实现的年度闹钟在闰年仍按365天触发?
故障原因
直接触发原因
你的代码混用了两种历法实例导致闰年判断失效:Calendar.getInstance()在部分定制系统、非中文公历地区默认返回的不是公历实例,可能是农历、和历等其他历法,你将非公历的年份传入公历GregorianCalendar的isLeapYear方法判断,会始终返回false,所以永远走365天的分支。
逻辑底层问题
你通过判断当前年份是否为闰年、手动加对应天数的方式实现年度提醒,逻辑本身就不成立:
- 如果你设置提醒的时间在闰年的2月29日之后,到下一年同一天的实际间隔就是365天,此时就算当前是闰年加366天反而会错后1天
- 无法处理2月29日的年度提醒在非闰年自动调整到2月28日的需求
修复方案
不要手动计算年度间隔,直接调用Calendar自带的年份增减方法,系统会自动处理历法、闰年、日期调整逻辑,代码如下:
mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); Intent intent1 = new Intent(context, AlarmReceiver.class); intent1.putExtra(ReminderEditActivity.EXTRA_REMINDER_ID, Integer.toString(mReceivedID)); // Android 12及以上必须明确指定FLAG_IMMUTABLE或FLAG_MUTABLE,否则PendingIntent创建失败 mPendingIntent = PendingIntent.getBroadcast(context, mReceivedID, intent1, PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE); // 统一使用公历实例避免历法差异 GregorianCalendar cal = (GregorianCalendar) GregorianCalendar.getInstance(); // 直接增加1年,自动处理闰年逻辑 cal.add(Calendar.YEAR, 1); mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), mPendingIntent);
补充说明:Android 12及以上系统需要申请SCHEDULE_EXACT_ALARM权限才能正常触发精确闹钟。
内容的提问来源于stack exchange,提问作者sai
相关产品推荐
相关产品推荐

