背景程序可能會耗用大量記憶體和電量。舉例來說,隱式廣播可能會啟動多個已註冊監聽的背景程序,即使這些程序可能執行少量工作,這會對裝置效能和使用者體驗產生重大影響。
為避免系統限制,請務必使用正確的 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 的電池用量」說明文件。