系統對背景工作的限制

背景程序可能會耗用大量記憶體和電量。舉例來說,隱式廣播可能會啟動多個已註冊監聽的背景程序,即使這些程序可能執行少量工作,也可能會對裝置效能和使用者體驗產生重大影響。

為避免系統限制,請務必為背景工作使用正確的 API。請參閱「背景工作總覽」說明文件,瞭解如何根據需求選擇合適的 API。

使用者啟動限制

如果應用程式表現出 Android Vitals 中描述的部分不良行為,系統會提示使用者限制該應用程式存取系統資源。

如果系統發現應用程式耗用過多資源,就會通知使用者並提供選項來限制應用程式的動作。可能觸發這類通知的行為包括:

  1. Wake Lock 過多:在螢幕關閉時,持續 1 小時的 1 個部分 Wake Lock
  2. 背景服務過多:應用程式指定 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_PICTUREACTION_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 最佳化電池用量」說明文件。