背景程序可能會耗用大量記憶體和電量。舉例來說,隱式廣播可能會啟動多個已註冊監聽的背景程序,即使這些程序可能執行少量工作,也可能會對裝置效能和使用者體驗產生重大影響。
為避免系統限制,請務必為背景工作使用正確的 API。請參閱「背景工作總覽」說明文件,瞭解如何根據需求選擇合適的 API。
使用者啟動限制
如果應用程式表現出 Android Vitals 中描述的部分不良行為,系統會提示使用者限制該應用程式存取系統資源。
如果系統發現應用程式耗用過多資源,就會通知使用者並提供選項來限制應用程式的動作。可能觸發這類通知的行為包括:
- Wake Lock 過多:在螢幕關閉時,持續 1 小時的 1 個部分 Wake Lock
- 背景服務過多:應用程式指定 API 26 以下級別,且提供的背景服務過多
精確的限制項目由裝置製造商決定。舉例來說,在 Android 開放原始碼計畫版本中,除非受限制的應用程式在前景執行,否則無法執行工作、觸發鬧鐘或使用網路。
接收網路活動廣播訊息的限制
如果應用程式註冊要在資訊清單中接收 CONNECTIVITY_ACTION 廣播訊息,就不會收到這類訊息,且依賴這類廣播訊息的程序也不會啟動。如果應用程式想要監聽網路變更,或者在裝置連上非計量付費的網路時執行大量網路活動,這可能就會造成問題。Android 架構已提供數種可處理這項限制的解決方式,但需要根據應用程式的需求選擇適當解決方案。
排定非計量付費連線時的工作
建構 WorkRequest 時,請新增 NetworkType.UNMETERED Constraint。
fun scheduleWork(context: Context) {
val workManager = WorkManager.getInstance(context)
val workRequest = OneTimeWorkRequestBuilder<MyWorker>()
.setConstraints(
Constraints.Builder()
.setRequiredNetworkType(NetworkType.UNMETERED)
.build()
)
.build()
workManager.enqueue(workRequest)
}
符合工作的條件時,應用程式會收到回呼,在指定的 Worker 類別中執行 doWork() 方法。
在應用程式執行時監控網路連線
執行中的應用程式仍可使用已註冊的 BroadcastReceiver 監聽 CONNECTIVITY_CHANGE。不過,ConnectivityManager API 提供了更強大的方法,只有在符合指定網路條件時才要求回呼。
NetworkRequest 物件會根據 NetworkCapabilities 定義網路回呼的參數。您可以使用 NetworkRequest.Builder 類別建立 NetworkRequest 物件。registerNetworkCallback 接著會將 NetworkRequest 物件傳遞至系統。符合網路條件時,應用程式會收到回呼,執行其 ConnectivityManager.NetworkCallback 類別中定義的 onAvailable() 方法。
應用程式會持續收到回呼,直到應用程式結束或呼叫 unregisterNetworkCallback() 為止。
接收圖片和影片廣播訊息的限制
應用程式無法傳送及接收 ACTION_NEW_PICTURE 或 ACTION_NEW_VIDEO 廣播訊息。如果必須喚醒多個應用程式來處理新的圖片或影片,這項限制有助於減輕對應用程式效能和使用者體驗的影響。
判別觸發工作的內容授權單位
WorkerParameters 可讓應用程式接收觸發工作的內容授權單位和 URI 相關實用資訊:
List<Uri> getTriggeredContentUris()
傳回觸發工作的 URI 清單。如果沒有任何 URI 觸發工作 (例如工作因截止期限或其他原因而觸發),或者發生變更的 URI 數量大於 50,這個陣列都會是空白。
List<String> getTriggeredContentAuthorities()
傳回觸發工作的內容主機名稱字串清單。如果傳回的清單不是空白,請使用 getTriggeredContentUris() 擷取已變更 URI 的詳細資料。
下列程式碼範例會覆寫 CoroutineWorker.doWork() 方法,並記錄觸發工作的內容授權單位和 URI:
class MyWorker(
appContext: Context,
params: WorkerParameters
): CoroutineWorker(appContext, params)
override suspend fun doWork(): Result {
StringBuilder().apply {
append("Media content has changed:\n")
params.triggeredContentAuthorities
.takeIf { it.isNotEmpty() }
?.let { authorities ->
append("Authorities: ${authorities.joinToString(", ")}\n")
append(params.triggeredContentUris.joinToString("\n"))
} ?: append("(No content)")
Log.i(TAG, toString())
}
return Result.success()
}
}
在系統限制下測試應用程式
對應用程式進行最佳化調整,改善在低記憶體裝置上或記憶體不足時的執行效能和使用者體驗。移除背景服務的依附元件以及在資訊清單註冊的隱式廣播接收器,有助於提高應用程式在這類裝置上的執行效能。建議您對應用程式進行最佳化調整,在執行時完全不要使用這些背景程序。
您可以使用一些額外的 Android Debug Bridge (ADB) 指令,在停用這些背景程序後測試應用程式行為:
如要模擬無法使用隱式廣播和背景服務的情況,請輸入下列指令:
$ adb shell cmd appops set <package_name> RUN_IN_BACKGROUND ignore如要重新啟用隱式廣播和背景服務,請輸入下列指令:
$ adb shell cmd appops set <package_name> RUN_IN_BACKGROUND allow
進一步最佳化應用程式
如要瞭解其他最佳化背景工作行為的實用方法,請參閱「針對工作排程 API 最佳化電池用量」說明文件。