
本文介绍如何在 android 应用中稳定、可靠地实现每日 1–3 次区间性通知(如 9–11 点、13–18 点、20–22 点),推荐使用 workmanager 替代已弃用且受系统限制的 alarmmanager.setrepeating(),兼顾兼容性、省电策略适配与后台执行可靠性。
本文介绍如何在 android 应用中稳定、可靠地实现每日 1–3 次区间性通知(如 9–11 点、13–18 点、20–22 点),推荐使用 workmanager 替代已弃用且受系统限制的 alarmmanager.setrepeating(),兼顾兼容性、省电策略适配与后台执行可靠性。
在 Android 8.0(API 26)及以上版本中,系统对后台任务和精确闹钟(AlarmManager.setExact() 及 setRepeating())施加了严格限制:应用进入缓存状态后,未启动的 Alarm 将被系统清除;而 setRepeating() 自 API 19 起已被标记为“不推荐使用”,在 Android 9+ 上完全失效。您当前基于 onCreate() 和 BroadcastReceiver 的手动重调度方案,本质上依赖前台活跃或用户频繁打开 App,因此在长期未使用后通知“消失”是典型表现——这并非代码错误,而是系统行为。
✅ 推荐方案:使用 WorkManager 实现鲁棒的周期性通知
WorkManager 是 Android 官方推荐的后台任务调度 API,具备以下关键优势:
- ✅ 自动适配不同 Android 版本(兼容 API 14+)
- ✅ 内置电池优化豁免逻辑(无需用户手动关闭省电模式)
- ✅ 支持约束条件(如
NetworkType.CONNECTED、BatteryNotLow) - ✅ 周期性任务自动持久化,即使设备重启仍可恢复(需设置
setExpedited(false)+setInitialDelay()) - ✅ 多个独立
PeriodicWorkRequest可并行运行,天然支持多时段通知
? 实现步骤(以每日三段区间通知为例)
1. 添加依赖(app/build.gradle)
implementation 'androidx.work:work-runtime-ktx:2.9.0'
2. 创建通知 Worker 类
public class DailyNotificationWorker extends CoroutineWorker {
private static final String KEY_NOTIFICATION_SLOT = "notification_slot";
public DailyNotificationWorker(@NonNull Context context, @NonNull WorkerParameters params) {
super(context, params);
}
@NonNull
@Override
public Result doWork() {
int slot = getInputData().getInt(KEY_NOTIFICATION_SLOT, 0);
Context context = getApplicationContext();
// 根据 slot 发送对应时段的通知(例如:0→早间,1→午后,2→晚间)
sendNotificationForSlot(context, slot);
// 返回 SUCCESS,WorkManager 将按周期自动重复执行
return Result.success();
}
private void sendNotificationForSlot(Context context, int slot) {
String title, content;
int notificationId;
switch (slot) {
case 0:
title = "早安提醒";
content = "新的一天,从专注开始!";
notificationId = 101;
break;
case 1:
title = "午后小憩";
content = "记得起身活动,保护视力哦~";
notificationId = 102;
break;
case 2:
title = "晚间总结";
content = "回顾今日目标完成情况?";
notificationId = 103;
break;
default:
return;
}
createNotificationChannel(context);
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, CHANNEL_ID)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle(title)
.setContentText(content)
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setAutoCancel(true)
.setContentIntent(createStartIntent(context));
NotificationManagerCompat.from(context).notify(notificationId, builder.build());
}
}3. 首次调度(建议在 Application.onCreate() 或首次启动时调用)
private void scheduleDailyNotifications() {
// 早间通知:目标时间 10:00(取 9–11 区间中点,提升命中率)
scheduleSlotWork(0, 10, 0); // slot=0, 10:00
// 午间通知:15:30(13–18 区间中点)
scheduleSlotWork(1, 15, 30);
// 晚间通知:21:00(20–22 区间中点)
scheduleSlotWork(2, 21, 0);
}
private void scheduleSlotWork(int slot, int hour, int minute) {
Calendar now = Calendar.getInstance();
Calendar target = Calendar.getInstance();
target.set(Calendar.HOUR_OF_DAY, hour);
target.set(Calendar.MINUTE, minute);
target.set(Calendar.SECOND, 0);
target.set(Calendar.MILLISECOND, 0);
// 若目标时间已过今日,则顺延至明日
if (target.before(now)) {
target.add(Calendar.DAY_OF_MONTH, 1);
}
long initialDelay = target.getTimeInMillis() - now.getTimeInMillis();
Data inputData = new Data.Builder()
.putInt(KEY_NOTIFICATION_SLOT, slot)
.build();
PeriodicWorkRequest workRequest = new PeriodicWorkRequest.Builder(
DailyNotificationWorker.class,
24, TimeUnit.HOURS) // 固定 24 小时周期(不可小于 15 分钟)
.setInitialDelay(initialDelay, TimeUnit.MILLISECONDS)
.setInputData(inputData)
.setConstraints(new Constraints.Builder()
.setRequiresBatteryNotLow(true)
.build())
.build();
WorkManager.getInstance(getApplicationContext())
.enqueueUniquePeriodicWork(
"daily_notification_slot_" + slot,
ExistingPeriodicWorkPolicy.KEEP,
workRequest
);
}⚠️ 关键注意事项
-
时间精度:
PeriodicWorkRequest不保证毫秒级准时(尤其在低电量/Doze 模式下),但会在约束满足后尽快执行,适合“区间提醒”场景,反比AlarmManager更稳定; -
最小周期限制:
PeriodicWorkRequest最小间隔为 15 分钟(setRepeatInterval(15, MINUTES)),因此“每日一次”必须设为24, HOURS; -
唯一性保障:使用
enqueueUniquePeriodicWork(..., KEEP)可避免重复注册,无需手动检查是否已存在; -
权限与渠道:Android 8.0+ 必须提前创建
NotificationChannel(您的代码已正确实现);Android 13+ 需动态申请POST_NOTIFICATIONS权限(您的权限请求逻辑合理,建议在scheduleDailyNotifications()前校验); -
调试技巧:启用
adb shell dumpsys jobscheduler查看 WorkManager 任务状态;使用WorkManagerTestDriver进行单元测试。
通过 WorkManager 替代 AlarmManager,您将获得 Telegram、Duolingo 等成熟应用所依赖的底层稳定性——它不追求“绝对准时”,而确保“必达”与“省电共存”。对于用户感知的“每天固定时段提醒”,区间中点 + 周期性调度,正是兼顾体验与系统规范的最佳平衡点。


















