應用程式在背景執行時,會耗用裝置的部分有限資源,例如 RAM。這可能會導致使用者體驗不佳,尤其是當使用者使用需要大量資源的應用程式時,例如玩遊戲或觀看影片。為改善使用者體驗,Android 8.0 (API 級別 26) 會限制應用程式在背景執行時可執行的作業。本文件將說明作業系統的變更內容,以及如何更新應用程式,讓應用程式在新的限制下正常運作。
總覽
許多 Android 應用程式和服務可以同時執行。舉例來說,使用者可能在一個視窗中玩遊戲,同時在另一個視窗中瀏覽網頁,並使用第三方應用程式播放音樂。同時執行的應用程式越多,系統負載就越大。如果其他應用程式或服務在背景執行,系統會承受額外負載,導致使用者體驗不佳,例如音樂應用程式可能會突然關閉。
為降低發生這些問題的機率,Android 8.0 會限制應用程式在使用者未直接與其互動時可執行的操作。應用程式會受到以下兩種限制:
背景服務限制:應用程式閒置時,其使用背景服務受到限制。這項規定不適用於使用者較易察覺的前景服務。
廣播限制:除了少數例外狀況,應用程式無法使用資訊清單註冊隱含廣播。他們仍可在執行階段註冊這些廣播,並使用資訊清單註冊明確廣播和專門針對其應用程式放送的廣播。
在大多數情況下,應用程式可以使用 JobScheduler
工作來解決這些限制。此方法可讓應用程式在非執行中時安排工作,但仍讓系統有餘裕的時間安排這些工作,不會影響使用者體驗。Android 8.0 對 JobScheduler
進行了多項改善,方便您使用排程工作取代服務和廣播接收器;詳情請參閱「JobScheduler 改善項目」。
背景服務限制
在背景執行的服務可能會耗用裝置資源,導致使用者體驗不佳。為減輕這個問題,系統會對服務套用多項限制。
系統會區分前景和背景應用程式。(為服務限制目的而定義的背景與記憶體管理所使用的定義不同;應用程式可能在記憶體管理方面屬於背景,但在啟動服務方面屬於前景)。如果滿足下列任一條件,系統就會將應用程式視為處於前景:
- 無論活動是否已啟動或暫停,都會顯示活動。
- 它具有前景服務。
- 另一個前景應用程式會連結至應用程式,方法是繫結至其中一個服務,或使用其中一個內容供應器。舉例來說,如果其他應用程式繫結至以下項目,應用程式就會處於前景:
- IME
- 桌布服務
- 通知接聽器
- 語音或文字服務
如果上述條件皆不成立,系統就會視為應用程式處於背景。
應用程式在前景執行時,可以自由建立及執行前景和背景服務。應用程式進入背景後,仍可在幾分鐘的時間內建立及使用服務。在該時間結束後,系統會將應用程式視為閒置。此時,系統會停止應用程式的背景服務,就像應用程式呼叫服務的 Service.stopSelf()
方法一樣。
在某些情況下,系統會將背景應用程式置於暫時許可清單中幾分鐘。應用程式在許可清單中時,可以不受限制地啟動服務,且其背景服務也能執行。應用程式處理使用者可見的作業時,就會列入許可清單,例如:
- 處理高優先順序的 Firebase 雲端通訊 (FCM) 訊息。
- 接收廣播訊息,例如簡訊/多媒體訊息。
- 從通知執行
PendingIntent
。 - 在 VPN 應用程式將自己提升至前景之前,啟動
VpnService
。
在許多情況下,應用程式可以使用 JobScheduler
工作取代背景服務。舉例來說,即使應用程式未在前景執行,CoolPhotoApp 仍需要檢查使用者是否收到朋友分享的相片。先前,應用程式會使用背景服務,透過應用程式的雲端儲存空間進行檢查。為了遷移至 Android 8.0 (API 級別 26),開發人員會將背景服務取代為定期工作,該工作會定期啟動、查詢伺服器,然後關閉。
在 Android 8.0 之前,建立前景服務的一般做法是建立背景服務,然後將該服務提升至前景。在 Android 8.0 中,系統不允許背景應用程式建立背景服務,因此會產生複雜性。因此,Android 8.0 推出了新方法 startForegroundService()
,可在前景啟動新服務。系統建立服務後,應用程式有五秒的時間呼叫服務的 [startForeground()
](/reference/android/app/Service#startForeground(int, android.app.Notification) 方法,以顯示新服務的使用者可見通知。如果應用程式在時間限制內「未」呼叫 startForeground()
,系統會停止服務,並宣告應用程式發生「ANR」。
廣播限制
如果應用程式註冊接收廣播,應用程式的接收器會在每次廣播傳送時耗用資源。如果太多應用程式註冊接收系統事件廣播,就可能會發生問題。觸發廣播的系統事件可能會導致所有應用程式快速連續使用資源,進而影響使用者體驗。為減輕這項問題的影響,Android 7.0 (API 級別 24) 對廣播訊息設下限制,如「背景最佳化」一文所述。Android 8.0 (API 級別 26) 會進一步強化這些限制。
- 指定 Android 8.0 以上版本為目標版本的應用程式,無法再在資訊清單中註冊隱含廣播訊息的廣播接收器,除非廣播訊息僅限於該應用程式。隱含廣播是指未指定應用程式中特定元件的廣播。舉例來說,
ACTION_PACKAGE_REPLACED
會傳送至所有應用程式中所有已註冊的事件監聽器,讓他們知道裝置上的某些套件已遭取代。由於廣播訊息是隱含的,因此不會傳送至指定 Android 8.0 以上版本的應用程式中,透過資訊清單註冊的接收器。ACTION_MY_PACKAGE_REPLACED
也是隱含廣播,但由於這項廣播只會傳送至套件已遭取代的應用程式,因此會傳送至資訊清單註冊的接收器。 - 應用程式可繼續在資訊清單中註冊明確的廣播訊息。
- 應用程式可以在執行階段使用
Context.registerReceiver()
,為任何廣播訊息註冊接收端,無論是隱含或明確廣播訊息皆可。 - 需要簽章權限的廣播訊息不受此限制,因為這類廣播訊息只會傳送至使用相同憑證簽署的應用程式,而不會傳送至裝置上的所有應用程式。
在許多情況下,先前為隱含廣播註冊的應用程式可以使用 JobScheduler
工作來取得類似功能。舉例來說,社群媒體相片應用程式可能需要不時清理資料,並且偏好在裝置連上充電器時執行這項作業。先前,應用程式會在資訊清單中為 ACTION_POWER_CONNECTED
註冊接收器;當應用程式收到該廣播訊息時,會檢查是否需要清理。為了遷移至 Android 8.0 以上版本,應用程式會從資訊清單中移除該接收器。相反地,應用程式會排定清理工作,在裝置閒置且充電時執行。
遷移指南
根據預設,這些變更只會影響指定 Android 8.0 (API 級別 26) 以上版本的應用程式。不過,即使應用程式指定的 API 級別低於 26,使用者仍可透過「設定」畫面為任何應用程式啟用這些限制。您可能需要更新應用程式,以符合新的限制。
檢查應用程式如何使用服務。如果應用程式在閒置時需要在背景執行的服務,您就必須取代這些服務。可能的解決方案包括:
- 如果應用程式需要在背景執行時建立前景服務,請使用
startForegroundService()
方法,而非startService()
。 - 如果使用者可察覺到該服務,請將其設為前景服務。舉例來說,播放音訊的服務一律應為前景服務。請使用
startForegroundService()
方法,而非startService()
建立服務。 - 找出方法,透過排程工作複製服務的功能。如果服務不會立即執行使用者可察覺的作業,通常可以改用排程工作。
- 使用 FCM 在網路事件發生時有選擇地喚醒應用程式,而非在背景輪詢。
- 延後背景工作,直到應用程式自然顯示在前景為止。
檢查應用程式資訊清單中定義的廣播接收器。如果您的資訊清單為受影響的隱含廣播聲明接收器,則必須將其取代。可能的解決方案包括:
- 請在執行階段呼叫
Context.registerReceiver()
,而非在資訊清單中宣告接收器。 - 使用排程工作來檢查可能會觸發隱含廣播的條件。