不同時註冊多個鬧鐘,而是維護一個按時間排序的任務列表,只為最近的一個任務設置鬧鐘;觸發後執行並移除,再為下一個任務設置。
class AlarmTask implements Comparable<AlarmTask> {
long triggerTime; // 毫秒時間戳
String id; // 業務唯一標識
Intent intent; // 執行動作
// getters/setters
@Override public int compareTo(AlarmTask o) {
return Long.compare(this.triggerTime, o.triggerTime);
}
}
// 全局有序集合(線程安全)
ConcurrentSkipListSet<AlarmTask> taskQueue = new ConcurrentSkipListSet<>();
taskQueue,若新任務成為首個 → setExact() 設置鬧鐘。taskQueue 移除,若被刪除的是首個 → 取消舊鬧鐘,為新首個設置。public class AlarmReceiver extends BroadcastReceiver {
@Override public void onReceive(Context ctx, Intent intent) {
AlarmTask task = taskQueue.pollFirst(); // 取出並移除首個
if (task != null) {
ctx.startService(task.intent); // 或 sendBroadcast
scheduleNext(ctx); // 為新首個設置鬧鐘
}
}
private void scheduleNext(Context ctx) {
AlarmTask next = taskQueue.peekFirst();
if (next != null) {
AlarmManager am = (AlarmManager) ctx.getSystemService(ALARM_SERVICE);
am.setExact(AlarmManager.RTC_WAKEUP, next.triggerTime,
PendingIntent.getBroadcast(ctx, 0, new Intent(ctx, AlarmReceiver.class), FLAG_IMMUTABLE));
}
}
}
id ↔ AlarmTask.id,刪除/修改按鈕直接操作 taskQueue。taskQueue 顯示剩餘任務。| 傳統多鬧鐘 | 單列表輪詢 |
|---|---|
| 系統鬧鐘數 = 任務數,受限 500+ 上限 | 始終只有 1 個系統鬧鐘,無上限壓力 |
| 增刪改需逐個 PendingIntent 操作 | 只操作隊首,邏輯極簡 |
| 重啟後需遍歷恢復所有 | 啟動時讀取持久化隊列,僅恢復隊首 |
Android 官方文檔明確建議:「盡量減少鬧鐘數量」。單列表輪詢法完美契合,且代碼量最少、邏輯最清晰。