
本文介绍如何基于用户选择的时间,结合当前日期判断工作日或周末,使用 alarmmanager 精准调度差异化本地通知,涵盖日历判断逻辑、闹钟触发策略及关键注意事项。
本文介绍如何基于用户选择的时间,结合当前日期判断工作日或周末,使用 alarmmanager 精准调度差异化本地通知,涵盖日历判断逻辑、闹钟触发策略及关键注意事项。
在 Android 中实现“工作日 vs 周末”差异化本地通知,核心在于动态识别目标触发日期的星期属性,并据此加载不同通知内容(如标题、图标、渠道、行为等)。虽然 AlarmManager 本身不直接支持按周几重复,但可通过组合 Calendar 判断 + 多次独立 PendingIntent 设置(或单次触发后自调度)来灵活实现。
✅ 正确判断工作日/周末的推荐方式
避免仅依赖当前时间(Calendar.getInstance()),而应在每次计算下次通知触发时刻时,动态构建目标 Calendar 实例,并校验其 DAY_OF_WEEK:
fun getTargetCalendar(selectedHour: Int, selectedMinute: Int, isWeekdayOnly: Boolean = true): Calendar? {
val calendar = Calendar.getInstance().apply {
// 清除秒、毫秒,确保精确到分钟
set(Calendar.SECOND, 0)
set(Calendar.MILLISECOND, 0)
set(Calendar.HOUR_OF_DAY, selectedHour)
set(Calendar.MINUTE, selectedMinute)
}
// 向前/向后查找下一个符合条件的日期(避免当天已错过)
while (true) {
val dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK)
val isWeekend = dayOfWeek == Calendar.SATURDAY || dayOfWeek == Calendar.SUNDAY
val match = if (isWeekdayOnly) {
dayOfWeek in Calendar.MONDAY..Calendar.FRIDAY
} else {
isWeekend
}
if (match && calendar.timeInMillis > System.currentTimeMillis()) {
return calendar
}
calendar.add(Calendar.DAY_OF_MONTH, 1) // 查找下一天
}
}
⚙️ 配合 AlarmManager 实现差异化调度
为工作日与周末分别注册独立 PendingIntent(推荐):
使用不同requestCode和Intentaction(如"NOTIFY_WEEKDAY"/"NOTIFY_WEEKEND"),确保互不覆盖;-
设置一次性 Alarm(RTC_WAKEUP):
val weekdayCal = getTargetCalendar(hour, minute, isWeekdayOnly = true) val weekendCal = getTargetCalendar(hour, minute, isWeekdayOnly = false) val weekdayIntent = Intent(context, NotificationReceiver::class.java).apply { action = "NOTIFY_WEEKDAY" putExtra("type", "weekday") } val weekdayPending = PendingIntent.getBroadcast( context, 1001, weekdayIntent, PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_ONE_SHOT ) alarmManager.setExactAndAllowWhileIdle( AlarmManager.RTC_WAKEUP, weekdayCal?.timeInMillis ?: 0, weekdayPending ) -
在 BroadcastReceiver 中发送对应通知:
class NotificationReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { val type = intent.getStringExtra("type") // "weekday" or "weekend" val notification = when (type) { "weekday" -> buildWeekdayNotification(context) "weekend" -> buildWeekendNotification(context) else -> return } NotificationManagerCompat.from(context).notify(1, notification) // ✅ 重新调度下一次(实现循环) rescheduleNext(context, type == "weekday") } }
⚠️ 关键注意事项
-
Android 8.0+ 限制后台执行:
setRepeating()已失效,必须使用setExactAndAllowWhileIdle()+ 手动重调度; -
勿复用相同 PendingIntent ID:工作日/周末 PendingIntent 必须使用不同
requestCode,否则后者会覆盖前者; -
时区与夏令时:
Calendar.getInstance()默认使用系统时区,若需跨时区一致性,建议显式设置calendar.timeZone = TimeZone.getTimeZone("UTC")并统一处理; -
用户权限:Android 12+ 需声明
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM"></uses-permission>并在运行时请求; -
测试验证:务必在真机上测试跨午夜、跨周末场景,模拟器可能忽略
ALLOW_WHILE_IDLE行为。
通过将日历逻辑封装为可复用的调度器,并结合 PendingIntent 的语义化区分与 BroadcastReceiver 的闭环重调度,即可稳健实现工作日与周末通知的差异化展示——既保持系统兼容性,又满足业务灵活性需求。











