首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

Android `Notification.when` 非發送時間?用 `AlarmManager` 實現定時通知

     編輯:程式設計綜合問答

誤區澄清

`Notification.when` **僅控制通知列表顯示的時間戳**(供使用者查看「幾點收到」),**不控制實際發送時間**。無論設為何值,`NotificationManager.notify()` 都是**立即**彈出。

正確實現定時/延遲通知

方案一:`AlarmManager` + `BroadcastReceiver`(標準、省電)

// 1. 定義接收器
public class NotificationPublisher extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        NotificationManager nm = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
        // 建立 NotificationCompat.Builder ...
        nm.notify(NOTIFICATION_ID, builder.build());
    }
}

// 2. 設定鬧鐘(API 19+ 用 setExact,API 23+ 需請求「鬧鐘與提醒」權限)
public void scheduleNotification(Context ctx, long triggerAtMillis) {
    Intent intent = new Intent(ctx, NotificationPublisher.class);
    intent.putExtra("title", "定時提醒");
    intent.putExtra("body", "時間到囉!");
    PendingIntent pi = PendingIntent.getBroadcast(ctx, 0, intent, PendingIntent.FLAG_IMMUTABLE);
    
    AlarmManager am = (AlarmManager) ctx.getSystemService(Context.ALARM_SERVICE);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        am.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, triggerAtMillis, pi);
    } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
        am.setExact(AlarmManager.RTC_WAKEUP, triggerAtMillis, pi);
    } else {
        am.set(AlarmManager.RTC_WAKEUP, triggerAtMillis, pi);
    }
}

方案二:`WorkManager`(延遲可容忍、需保證最終執行)

OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(NotificationWorker.class)
    .setInitialDelay(delayMillis, TimeUnit.MILLISECONDS)
    .build();
WorkManager.getInstance(ctx).enqueue(work);
    Worker 內發送通知,系統會在 Doze/待機模式下自動調度,適合「幾小時後提醒」等非精確場景。

方案三:前台服務 + `Handler`/`Timer`(極高精度、持續運行)

啟動 `Service.startForeground()` 顯示持續通知,內部用 `ScheduledExecutorService` 定時發送。缺點:常駐記憶體、耗電、Android 8+ 需 `FOREGROUND_SERVICE` 權限。

版本適配重點

Android 版本關鍵 API注意事項
5.0-5.1`setExact`Doze 模式未引入,準確度高
6.0-7.1`setExactAndAllowWhileIdle`Doze 維護窗口內批次執行
8.0+NotificationChannel + `setExactAndAllowWhileIdle`需建立 Channel,`IMPORTANCE_HIGH` 才會彈出浮動
12+ (API 31)`SCHEDULE_EXACT_ALARM` 權限用戶需在設定手動授予,否則 `setExact` 失效退化為 `setWindow`

測試指令

# 強制進入 Doze 測試
adb shell dumpsys deviceidle force-idle
# 查看已設定鬧鐘
adb shell dumpsys alarm | grep your.package.name

總結

忘掉 `Notification.when` 控制發送時間。用 `AlarmManager.setExactAndAllowWhileIdle` 做精確定時,用 `WorkManager` 做彈性延遲,配合 `NotificationChannel` 確保 Android 8+ 正常彈出。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved