iT邦幫忙

2025 iThome 鐵人賽

DAY 20
0

AlarmManagerService:排程與背景任務

前言

在行動裝置上,電源管理與背景任務的安排是系統效能與使用者體驗的關鍵。Android 系統中有一個重要的服務 —— AlarmManagerService,它負責管理定時任務 (Scheduled Tasks),讓應用程式能在特定時間被喚醒執行。
然而,隨著 Android 版本的演進,Google 為了省電引入了 Doze 模式、App Standby,並逐步鼓勵開發者使用 JobScheduler、WorkManager 取代過度依賴 AlarmManager 的行為。

AlarmManagerService 的角色

AlarmManagerService 位於 Android Framework 層級,由 SystemServer 啟動。它的主要職責包含:

  • 管理定時任務 (Alarms)
    • 提供應用程式透過 AlarmManager API 設定定時事件。
    • 可用於排程通知、背景同步、週期性檢查等。
  • 負責任務觸發
    • 在指定的時間或條件到達時,AlarmManagerService 會將事件分發給目標應用程式。
  • 與 PowerManagerService 協作
    • 當螢幕熄滅或裝置進入 Doze,Alarm 觸發會受到影響,需配合 省電策略 調整。
  • 跨進程管理
    • 提供系統服務接口,應用程式端呼叫 AlarmManager API,最終由 AlarmManagerService 統一管理。

架構與運作流程

[App 層] 
   |   AlarmManager API (setExact, setRepeating, etc.)
   v
[Framework 層]
   AlarmManagerService
       |-- AlarmStore (保存鬧鐘)
       |-- AlarmThread (專責處理事件)
   v
[Kernel 層]
   Alarm 驅動 (RTC, ELAPSED_REALTIME, etc.)
   v
[回調 App]
   BroadcastReceiver / PendingIntent
  1. Alarm 類型
    AlarmManager 支援不同的時間來源:
  • RTC
    • 基於「實際時間」(Real Time Clock),會受到時區與時間校正影響。
  • ELAPSED_REALTIME
    • 基於「系統開機後的時間」,不受手動改時影響。
  • WAKEUP 類型
    • 會強制喚醒裝置 (CPU/螢幕)。
  • NON-WAKEUP 類型
    • 僅在裝置醒著時觸發。
  1. 設定流程
  • App 透過 AlarmManager API 設定 Alarm。
  • AlarmManagerService 接收並存入 AlarmStore。
  • 當時間點到達,AlarmThread 驅動回調,觸發 PendingIntent。
  • App 的 BroadcastReceiver 被喚醒並執行任務。

API 與使用方式

  1. 設定一次性 Alarm
val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
val intent = Intent(context, MyReceiver::class.java)
val pendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0)

alarmManager.setExact(
    AlarmManager.RTC_WAKEUP,
    System.currentTimeMillis() + 60_000,
    pendingIntent
)

==>在 1 分鐘後觸發。

  1. 重複 Alarm
alarmManager.setRepeating(
    AlarmManager.ELAPSED_REALTIME_WAKEUP,
    SystemClock.elapsedRealtime() + 10_000,
    60_000,
    pendingIntent
)

==> 每分鐘觸發一次,但 Android 5.1 以後可能被合併 (batching)。

  1. 允許 Doze 中觸發
alarmManager.setExactAndAllowWhileIdle(
    AlarmManager.RTC_WAKEUP,
    System.currentTimeMillis() + 60_000,
    pendingIntent
)

==> 用於需要高優先級的任務,但 Google 不建議頻繁使用。

與 JobScheduler、WorkManager 的比較

隨著 Android 發展,Google 更傾向使用 JobScheduler 與 WorkManager,原因是它們能夠:

  • 自動配合省電模式
  • 支援網路條件、充電狀態等限制
  • 避免 AlarmManager 的濫用

比較表
機制 適用情境 特點
AlarmManager 精準定時、週期性事件 適合「提醒類事件」,不適合頻繁背景任務
JobScheduler 系統級任務排程 支援條件限制 (網路/充電)
WorkManager 跨版本任務排程 封裝 AlarmManager + JobScheduler,推薦使用

電源管理下的限制

Android 為了降低耗電,引入了一系列機制:

  1. Doze 模式
    在裝置長時間待機時,Alarm 會被延後。
    只有 setAndAllowWhileIdle、setExactAndAllowWhileIdle 可以有限度觸發。
  2. App Standby
    長時間未使用的應用程式,其 Alarm 會被延遲。
  3. Batching
    系統會合併多個 App 的 Alarm,一次喚醒 CPU,降低耗電。
  4. 限制策略
    Android 6.0 之後:週期性 Alarm 可能被合併。
    Android 12 之後:對 過度使用 setExact() 的 App 會限縮。

best practice

  • 避免頻繁 Alarm
    • 不要使用過短週期,例如每 1 分鐘喚醒,建議改用 JobScheduler/WorkManager。
  • 善用條件排程
    • 需要網路、充電時才同步 → JobScheduler 更合適。
  • 省電模式下要小心
    • 如果需要在 Doze 模式執行,請謹慎使用 setExactAndAllowWhileIdle(),避免過度耗電。
  • 背景同步建議
    • 使用 WorkManager + Firebase Cloud Messaging,避免單純依靠 AlarmManager。

圖表示意

  1. AlarmManager 與事件流程
[App 設定 Alarm]
        |
        v
[AlarmManagerService] --- 儲存於 AlarmStore
        |
        v
[AlarmThread 驅動]
        |
        v
[PendingIntent] ---> [BroadcastReceiver / Service]
  1. 與其他排程器的關係
           +-----------------+
           | AlarmManager    | --> 精準定時 (提醒/鬧鐘)
           +-----------------+
                    |
                    v
           +-----------------+
           | JobScheduler    | --> 系統條件 (網路/充電)
           +-----------------+
                    |
                    v
           +-----------------+
           | WorkManager     | --> 跨版本、推薦使用
           +-----------------+

summary

AlarmManagerService 是 Android 定時與排程的基礎服務,負責應用程式的鬧鐘與定時任務。
但隨著 Doze 與省電政策 的引入,AlarmManager 的能力受到限制。
Google 建議開發者改用 JobScheduler 或 WorkManager,避免濫用 AlarmManager。
對於開發者而言,AlarmManager 適合「通知、提醒」等精準事件,而長期背景工作應改用新排程框架。


上一篇
#18
系列文
安豬複習20
  1. 16
    #15
  2. 17
    #16
  3. 18
    #17
  4. 19
    #18
  5. 20
    #19
完整目錄
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言