背景程序可能會耗用大量記憶體和電量。舉例來說,隱式廣播可能會啟動多個已註冊監聽的背景程序,即使這些程序可能執行少量工作,也可能會對裝置效能和使用者體驗產生重大影響。
為避免系統限制,請務必為背景工作使用正確的 API。請參閱「背景工作總覽」說明文件,選擇符合需求的 API。
使用者啟動限制
如果應用程式出現 Android Vitals 中所述的一些不良行為,系統就會提示使用者限制該應用程式對系統資源的存取權。
如果系統發現應用程式耗用過多資源,就會通知使用者並提供選項來限制應用程式的動作。可能觸發這類通知的行為包括:
- Wake Lock 使用過度:在螢幕關閉時,持續 1 小時的 1 個部分 Wake Lock
- 背景服務過多:應用程式指定 API 26 以下級別,且提供的背景服務過多
精確的限制項目由裝置製造商決定。舉例來說,在 AOSP 版本中,除非受限制的應用程式在前景執行,否則無法執行工作、觸發鬧鐘或使用網路。
接收網路活動廣播訊息的限制
如果應用程式已註冊在其資訊清單中接收 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, private val 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 的電池用量」說明文件。