每次在后臺運行時,應(yīng)用都會消耗一部分有限的設(shè)備資源,例如 RAM。 這可能會影響用戶體驗,如果用戶正在使用占用大量資源的應(yīng)用(例如玩游戲或觀看視頻),影響尤為明顯。
為了提升用戶體驗,Android 8.0 對應(yīng)用在后臺運行時可以執(zhí)行的操作施加了限制。 本文檔說明了操作系統(tǒng)的一些變更,以及如何更新應(yīng)用以便在新限制下正常運行。
概覽
多個 Android 應(yīng)用和服務(wù)可以同時運行。 例如,用戶可以在一個窗口中玩游戲,同時在另一個窗口中瀏覽網(wǎng)頁,并使用第三個應(yīng)用播放音樂。
同時運行的應(yīng)用越多,對系統(tǒng)造成的負擔(dān)越大。 如果還有應(yīng)用或服務(wù)在后臺運行,這會對系統(tǒng)造成更大負擔(dān),進而可能導(dǎo)致用戶體驗下降;例如,音樂應(yīng)用可能會突然關(guān)閉。
為了降低發(fā)生這些問題的幾率,Android 8.0 對應(yīng)用在用戶不與其直接交互時可以執(zhí)行的操作施加了限制。
應(yīng)用在兩個方面受到限制:
- 后臺服務(wù)限制:處于空閑狀態(tài)時,應(yīng)用可以使用的后臺服務(wù)存在限制。 這些限制不適用于前臺服務(wù),因為前臺服務(wù)更容易引起用戶注意。
-
廣播限制:除了有限的例外情況,應(yīng)用無法使用清單注冊隱式廣播。 它們?nèi)匀豢梢栽谶\行時注冊這些廣播,并且可以使用清單注冊專門針對它們的顯式廣播。
注:默認情況下,這些限制僅適用于針對 O 的應(yīng)用。 不過,用戶可以從 Settings 屏幕為任意應(yīng)用啟用這些限制,即使應(yīng)用并不是以 O 為目標(biāo)平臺。
在大多數(shù)情況下,應(yīng)用都可以使用JobScheduler 作業(yè)克服這些限制。 這種方式讓應(yīng)用安排為在未活躍運行時執(zhí)行工作,不過仍能夠使系統(tǒng)可以在不影響用戶體驗的情況下安排這些作業(yè)。
Android 8.0 提供針對 JobScheduler 的多個改進,讓您可以更輕松地使用計劃作業(yè)取代服務(wù)和廣播接收器;如需了解詳細信息,請參閱 JobScheduler 改進。
后臺服務(wù)限制
在后臺中運行的服務(wù)會消耗設(shè)備資源,這可能降低用戶體驗。 為了緩解這一問題,系統(tǒng)對這些服務(wù)施加了一些限制。
系統(tǒng)可以區(qū)分 前臺 和 后臺 應(yīng)用。 (用于服務(wù)限制目的的后臺定義與內(nèi)存管理使用的定義不同;一個應(yīng)用按照內(nèi)存管理的定義可能處于后臺,但按照能夠啟動服務(wù)的定義又處于前臺。)如果滿足以下任意條件,應(yīng)用將被視為處于前臺:
- 具有可見 Activity(不管該 Activity 已啟動還是已暫停)。
- 具有前臺服務(wù)。
- 另一個前臺應(yīng)用已關(guān)聯(lián)到該應(yīng)用(不管是通過綁定到其中一個服務(wù),還是通過使用其中一個內(nèi)容提供程序)。 例如,如果另一個應(yīng)用綁定到該應(yīng)用的服務(wù),那么該應(yīng)用處于前臺:
- IME
- 壁紙服務(wù)
- 通知偵聽器
- 語音或文本服務(wù)
如果以上條件均不滿足,應(yīng)用將被視為處于后臺。
綁定服務(wù)不受影響,這些規(guī)則不會對綁定服務(wù)產(chǎn)生任何影響。 如果您的應(yīng)用定義了綁定服務(wù),則不管應(yīng)用是否處于前臺,其他組件都可以綁定到該服務(wù)。
處于前臺時,應(yīng)用可以自由創(chuàng)建和運行前臺服務(wù)與后臺服務(wù)。 進入后臺時,在一個持續(xù)數(shù)分鐘的時間窗內(nèi),應(yīng)用仍可以創(chuàng)建和使用服務(wù)。
在該時間窗結(jié)束后,應(yīng)用將被視為處于 空閑 狀態(tài)。 此時,系統(tǒng)將停止應(yīng)用的后臺服務(wù),就像應(yīng)用已經(jīng)調(diào)用服務(wù)的“Service.stopSelf()”方法。
在這些情況下,后臺應(yīng)用將被置于一個臨時白名單中并持續(xù)數(shù)分鐘。 位于白名單中時,應(yīng)用可以無限制地啟動服務(wù),并且其后臺服務(wù)也可以運行。
處理對用戶可見的任務(wù)時,應(yīng)用將被置于白名單中,例如:
- 處理一條高優(yōu)先級 Firebase 云消息傳遞 (FCM) 消息。
- 接收廣播,例如短信/彩信消息。
- 從通知執(zhí)行 PendingIntent。
在很多情況下,您的應(yīng)用都可以使用 JobScheduler 作業(yè)替換后臺服務(wù)。 例如,CoolPhotoApp 需要檢查用戶是否已經(jīng)從朋友那里收到共享的照片,即使該應(yīng)用未在前臺運行。
之前,應(yīng)用使用一種會檢查其云存儲的后臺服務(wù)。 為了遷移到 Android 8.0,開發(fā)者使用一個計劃作業(yè)替換了這種后臺服務(wù),該作業(yè)將按一定周期啟動,查詢服務(wù)器,然后退出。
在 Android 8.0 之前,創(chuàng)建前臺服務(wù)的方式通常是先創(chuàng)建一個后臺服務(wù),然后將該服務(wù)推到前臺。
Android 8.0 有一項復(fù)雜功能;系統(tǒng)不允許后臺應(yīng)用創(chuàng)建后臺服務(wù)。 因此,Android 8.0 引入了一種全新的方法,即 Context.startForegroundService(),以在前臺啟動新服務(wù)。
在系統(tǒng)創(chuàng)建服務(wù)后,應(yīng)用有五秒的時間來調(diào)用該服務(wù)的 startForeground() 方法以顯示新服務(wù)的用戶可見通知。
如果應(yīng)用在此時間限制內(nèi)未調(diào)用 startForeground(),則系統(tǒng)將停止服務(wù)并聲明此應(yīng)用為 ANR。
廣播限制
如果應(yīng)用注冊為接收廣播,則在每次發(fā)送廣播時,應(yīng)用的接收器都會消耗資源。 如果多個應(yīng)用注冊為接收基于系統(tǒng)事件的廣播,這會引發(fā)問題;觸發(fā)廣播的系統(tǒng)事件會導(dǎo)致所有應(yīng)用快速地連續(xù)消耗資源,從而降低用戶體驗。
為了緩解這一問題,Android 7.0(API 級別 25)對廣播施加了一些限制,如后臺優(yōu)化中所述。
Android 8.0 讓這些限制更為嚴(yán)格。
- 針對 Android 8.0 的應(yīng)用無法繼續(xù)在其清單中為隱式廣播注冊廣播接收器。 隱式廣播是一種不專門針對該應(yīng)用的廣播。 例如,ACTION_PACKAGE_REPLACED 就是一種隱式廣播,因為它將發(fā)送到注冊的所有偵聽器,讓后者知道設(shè)備上的某些軟件包已被替換。不過,ACTION_MY_PACKAGE_REPLACED 不是隱式廣播,因為不管已為該廣播注冊偵聽器的其他應(yīng)用有多少,它都會只發(fā)送到軟件包已被替換的應(yīng)用。
- 應(yīng)用可以繼續(xù)在它們的清單中注冊顯式廣播。
- 應(yīng)用可以在運行時使用 Context.registerReceiver() 為任意廣播(不管是隱式還是顯式)注冊接收器。
- 需要簽名權(quán)限的廣播不受此限制所限,因為這些廣播只會發(fā)送到使用相同證書簽名的應(yīng)用,而不是發(fā)送到設(shè)備上的所有應(yīng)用。
在許多情況下,之前注冊隱式廣播的應(yīng)用使用 JobScheduler 作業(yè)可以獲得類似的功能。
例如,一款社交照片應(yīng)用可能需要不時地執(zhí)行數(shù)據(jù)清理,并且傾向于在設(shè)備連接到充電器時執(zhí)行此操作。
之前,應(yīng)用已經(jīng)在清單中為 ACTION_POWER_CONNECTED 注冊了一個接收器;當(dāng)應(yīng)用接收到該廣播時,它會檢查清理是否必要。 為了遷移到 Android 8.0,應(yīng)用將該接收器從其清單中移除。
應(yīng)用將清理作業(yè)安排在設(shè)備處于空閑狀態(tài)和充電時運行。
注:很多隱式廣播當(dāng)前均已不受此限制所限。 應(yīng)用可以繼續(xù)在其清單中為這些廣播注冊接收器,不管應(yīng)用針對哪個 API 級別。 有關(guān)已豁免廣播的列表,請參閱隱式廣播例外。
遷移指南
默認情況下,這些更改僅影響針對 O 的應(yīng)用。 不過,用戶可以從 Settings 屏幕為任意應(yīng)用啟用這些限制,即使應(yīng)用并不是以 O 為目標(biāo)平臺。
您可能需要更新應(yīng)用,使其符合新限制。
了解您的應(yīng)用如何使用服務(wù)。 如果您的應(yīng)用依賴某些在它處于空閑時于后臺運行的服務(wù),您需要替換這些服務(wù)。
可能的解決方法包括:
- 如果處于后臺時您的應(yīng)用需要創(chuàng)建一個前臺服務(wù),請使用新的 NotificationManager.startServiceInForeground()方法,而不是創(chuàng)建一個后臺服務(wù),然后嘗試將其推到前臺。
- 如果服務(wù)容易被用戶注意,請將其設(shè)為前臺服務(wù)。 例如,播放音頻的服務(wù)始終應(yīng)為前臺服務(wù)。使用 NotificationManager.startServiceInForeground()而不是 startService() 創(chuàng)建服務(wù)。
- 尋找一種使用計劃作業(yè)實現(xiàn)服務(wù)功能的方式。 如果服務(wù)未在執(zhí)行容易立即被用戶注意到的操作,一般情況下,您都能夠使用計劃作業(yè)。
- 發(fā)生網(wǎng)絡(luò)事件時,請使用 FCM 選擇性地喚醒您的應(yīng)用,而不是在后臺輪詢。
- 在應(yīng)用正常處于前臺之前,請推遲后臺工作。
檢查在您應(yīng)用的清單中定義的廣播接收器。 如果您的清單為顯式廣播聲明了接收器,您必須予以替換。 可能的
解決方法包括:
- 通過調(diào)用 Context.registerReceiver() 而不是在清單中聲明接收器的方式在運行時創(chuàng)建接收器。
- 使用計劃作業(yè)檢查條件是否會觸發(fā)隱式廣播。
本文是Google官方文檔,原文鏈接請戳https://developer.android.com/about/versions/oreo/background