Android 系統在記憶體不足時會直接殺死進程(onDestroy()、onStop() 均不會被呼叫),導致依賴生命週期回調的上報邏輯失效。
onDestroy():使用者按 Home 進入後台,系統回收時不保證呼叫。onStop():Activity 切換、鎖屏皆會觸發,無法判斷「整個 App 退出」。Application.onTerminate():僅模擬器執行,實機從不調用。Service + START_STICKY:系統殺進程時 Service 也會被殺,重啟延遲不可控。┌─────────────┐ 定時/事件觸發 ┌──────────────┐
│ 業務邏輯層 │ ─────────────────────▶ │ 本地持久化 │ (SharedPreferences / MMKV / Room)
│ 產生上報資料 │ │ 寫入待發佇列 │
└─────────────┘ └──────┬───────┘
│
App 進程存活時 │ 後台執行緒/WorkManager
定期嘗試發送 ────────┘
│
App 冷啟動時 ▼
讀取待發佇列 ───▶ 發送補償請求
eventId(UUID)、payload(JSON)、createTime、retryCount。WorkManager 週期性作業(最小 15 分鐘)嘗試發送。Application.onCreate() 中啟動一次性 Worker 清理待發佇列。eventId 去重,客戶端發送成功後刪除本地記錄。// 1. 定義 Worker
class UploadWorker(ctx: Context, params: WorkerParameters) : CoroutineWorker(ctx, params) {
override suspend fun doWork(): Result {
val repo = ReportRepository.getInstance(applicationContext)
val pending = repo.getPendingReports(limit = 50)
pending.forEach { report ->
val success = ApiClient.upload(report.payload).await()
if (success) repo.delete(report.id) else repo.incrementRetry(report.id)
}
return if (pending.isEmpty()) Result.success() else Result.retry()
}
}
// 2. 入庫
fun saveReport(payload: String) {
val report = Report(UUID.randomUUID().toString(), payload, System.currentTimeMillis(), 0)
ReportRepository.getInstance(appContext).insert(report)
// 觸發即時上傳嘗試
WorkManager.getInstance(appContext).enqueueUniqueWork(
"upload_reports", ExistingWorkPolicy.REPLACE,
OneTimeWorkRequestBuilder<UploadWorker>().build()
)
}
// 3. 啟動補發 (Application.onCreate)
WorkManager.getInstance(this).enqueueUniqueWork(
"startup_upload", ExistingWorkPolicy.KEEP,
OneTimeWorkRequestBuilder<UploadWorker>().setInitialDelay(10, TimeUnit.SECONDS).build()
)
| 方案 | 優點 | 缺點 | 適用場景 |
|---|---|---|---|
| 定時持久化+補發 | 可靠、不依賴生命週期、支援重試 | 有延遲、需處理冪等 | 統計上報、日誌收集、非即時業務 |
| 前台 Service + Notification | 進程優先級高、較難被殺 | 常駐通知欄干擾使用者、系統仍可能殺 | 音樂播放、導航、即時通訊 |
| JobScheduler / AlarmManager 定時喚醒 | 系統級調度 | Android 7+ 限制多、精確度低 | 定期同步、備份 |
「系統殺進程時無法執行代碼」是 Android 系統設計鐵律。唯一可行之道是將「發送」與「業務產生」解耦:業務只負責「寫入本地佇列」,由獨立的背景機制(WorkManager)負責「讀取佇列並發送」。接受「有延遲、最終一致性」的現實,換取 99.9% 以上的送達率。