Kotlin安卓应用定时通知仅上午触发,下午PM时段不生效如何解决?
问题根因
你的代码核心问题是缺失12小时制到24小时制的转换逻辑:
- 界面展示用的是12小时制(带PM后缀),比如晚上8点你存入SharedPreferences的
asarTimeHour值是8,但你赋值用的Calendar.HOUR_OF_DAY是24小时制字段,值8对应上午8点,自然只会在上午触发。 - 两个潜在问题:如果设置时间早于当前系统时间,取到的是当天过去的时间,会导致定时直接触发或者延后到第二天;Android 12及以上版本PendingIntent必须加
FLAG_IMMUTABLE或FLAG_MUTABLE标识,否则定时会失效甚至崩溃。
修复方案
1. 新增上午/下午状态存储
用户选择时间时,除了存小时、分钟,额外存一个布尔字段isAsarTimePm,PM时段存true,AM时段存false,其余4个定时任务同理添加对应标识字段。
2. 小时制转换+时间有效性判断
给Calendar赋值时把12小时制转为24小时制,同时判断时间是否已过,已过则自动延后到第二天。
3. 兼容高版本安卓的PendingIntent规则
适配Android 12+的PendingIntent标识要求,同时将精度低的setInexactRepeating替换为准点生效的setExactAndAllowWhileIdle,更适合礼拜通知这类对时间精度要求高的场景。
修复后代码
定时触发逻辑代码
asrSwitch.setOnCheckedChangeListener { buttonView, isChecked -> if (isChecked){ editor.putBoolean("asarTimesSwitch",true) editor.putBoolean("asarTXT", true) editor.apply() asrSwitch.isChecked = true val asarTime = getSharedPreferences("saveSettingData", Context.MODE_PRIVATE) calender = Calendar.getInstance() // 取出存储的12小时制时间和时段标识 val saveHour = asarTime.getInt("asarTimeHour", 0) val isPm = asarTime.getBoolean("isAsarTimePm", false) val saveMinute = asarTime.getInt("asarTimeMinutes",0) // 转换为24小时制,处理12点的特殊边界 val hour24 = if (isPm) { if (saveHour == 12) 12 else saveHour + 12 } else { if (saveHour == 12) 0 else saveHour } calender[Calendar.HOUR_OF_DAY] = hour24 calender[Calendar.MINUTE] = saveMinute calender[Calendar.SECOND] = 0 calender[Calendar.MILLISECOND] = 0 // 时间已过则自动延后到第二天 if (calender.timeInMillis < System.currentTimeMillis()) { calender.add(Calendar.DAY_OF_MONTH, 1) } // 界面保持12小时制展示 asrTxt.text = "$saveHour:$saveMinute ${if (isPm) "PM" else "AM"}" alarmAsr() }else{ editor.putBoolean("asarTimesSwitch",false) editor.putBoolean("asarTXT", false) editor.apply() asrSwitch.isChecked = false asrTxt.text = " " } }
定时任务代码
fun alarmAsr(){ alarmManager = getSystemService(ALARM_SERVICE) as AlarmManager val i = Intent(this, asarBroadcastReceiver::class.java) // 兼容Android 12+的PendingIntent标识要求 val flag = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE } else { PendingIntent.FLAG_UPDATE_CURRENT } pendingIntent = PendingIntent.getBroadcast(this, 4, i, flag) // 准点触发,支持低电模式生效 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { alarmManager.setExactAndAllowWhileIdle( AlarmManager.RTC_WAKEUP, calender.timeInMillis, pendingIntent ) } else { alarmManager.setExact( AlarmManager.RTC_WAKEUP, calender.timeInMillis, pendingIntent ) } }
如果需要每天重复触发,只需在对应广播接收器的onReceive方法里,触发通知后重新调用一次定时设置方法,即可注册第二天的准点通知。
内容的提问来源于stack exchange,提问作者Abood
相关产品推荐
相关产品推荐

