背景作業的系統限制

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

為避免系統限制,請務必使用正確的 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 的電池用量」說明文件。