跳至主要內容
YIM NEWS
† 最新報導
科技 科普

App 被系統殺掉之後:Android 的「喚起」與「常駐」,其實是同一套設計

刊登 2026/11/10 13:15 閱讀約 5 分鐘 全站第 1,571 篇

2026 年 11 月 7 日,掘金出現一篇近四十分鐘閱讀量的長文,作者「瘋華整貓」把一個多數 Android 開發者都踩過的坑,從頭到尾重做了一遍:使用者從簡訊連結點進 App,頁面開對了,按返回鍵卻直接退回桌面;改從通知點進來,參數又丟了;等把 targetSdk 升到 34,前臺服務一啟動就拋 SecurityException。作者得出的結論很直白:這看起來是三個 bug,實際上是同一件事沒設計好。

這件事技術味很重,但它影響的其實是很日常的體驗:你點一則簡訊裡的網銀連結、收一則外送通知、背景同步一筆資料,中間每一步都走在這套機制上。

先把三個常被混用的詞分開

平常說的「喚起」「常駐」「保活」,在系統眼裡是三件不同的事。喚起,是把一個不存在或在背景的進程,變成「有畫面或有任務在跑」,對應的 API 是 Intent、PendingIntent、App Links 和 startForegroundService。常駐,是使用者離開畫面後,任務還能照預期持續,靠的是 Service 搭配 startForeground 和 WorkManager。至於過去常聽到的「保活」,指的是讓進程盡量別被殺,用的是雙進程守護、一像素 Activity、無聲音頻這類手法。

作者的判斷是:這些老辦法已經不可靠,也不合規。Android 8 之後系統一版一版地堵,國產 ROM 的省電策略比原生更嚴,費盡力氣換來的往往只是「多活幾分鐘」,代價是耗電榜單上的名字、負評,以及合規檢查時被點名。他選的是另一條路:讓背景任務看得見、停得下,進程死了能從斷點接著跑。

進程的「三種活法」,決定參數丟不丟

文章裡最有價值的一段,是把「進程活著」拆成三種狀態。冷啟動:點圖示、點連結或推播,Application.onCreate 會執行,Activity 全新建。溫啟動:從最近任務切回,Activity 已被回收,Application.onCreate 不執行,要靠 savedInstanceState 恢復。熱啟動:從背景切回,singleTask 的 Activity 被復用,這時走的是 onNewIntent。

用個比喻:這就像去一間常去的店。第一次上門,店員從頭招呼你(冷啟動);你出去買個東西再回來,店員記得你點過什麼(溫啟動);而你只是走去隔壁桌再看一次菜單,店不會重新開張(熱啟動)。三種情境該做的事完全不同。

作者觀察到最常見的線上問題,就是只在 onCreate 裡讀 intent.data。熱啟動時 Activity 被復用,走的是 onNewIntent,連結參數就這樣靜默丟失,而且不報任何錯。這也是為什麼「按返回鍵直接退回桌面」和「通知參數丟失」會同時出現:多個喚起入口各寫各的,交界處一定漏。他的解法是讓所有喚起路徑只走同一個 dispatch 入口。

那行 SecurityException 在說什麼

targetSdk 升到 34 之後,前臺服務一啟動就拋出 Starting FGS requires a valid type,這是近年 Android 收緊背景執行的具體表現。系統要求開發者明確宣告前臺服務的類型,讓使用者知道 App 在背景做的是定位、同步還是媒體播放。這與我們先前討論過的Android 圖層合成退化屬於同一種結構:問題常不在硬體,而在系統規則變了之後,應用沒跟著調整。

作者的原則可以整理成幾條:進程隨時會死,這是前提而非意外;不能丟的進度一律落碟;所有喚起路徑只有一個入口;背景在做的事必須讓使用者看得見、並且能停;每個與系統版本有關的行為都標清楚 API level。環境是 Kotlin、minSdk 26、targetSdk 35,同時要顧及 Android 16 的行為,只使用 AndroidX,沒有引入第三方 SDK。

所以呢

對開發者來說,這篇文章的價值在於換了個問法。與其問「怎麼讓進程不被殺」,不如問「進程被殺之後,使用者回到 App 時體驗接不接得起來」。前者是在跟系統對抗,後者是順著系統的規則設計。對一般使用者來說,下次看到某個 App 出現在耗電榜單前端、或背景行為神祕兮兮,那多半就是還在用舊思維做「保活」的產品。而一個把斷點落碟、通知透明、可隨時停止做好的 App,使用者感受到的通常只是「一切正常」,這恰恰是這套設計做對的樣子。

資料來源

  1. 01 參考來源 juejin.cn

本文使用 AI 協助整理或撰稿,引用與分析仍應依原始資料核對。

編輯政策 更正與勘誤