產品最新消息

不只單一功能:使用 CameraX 1.5 確保功能組合

閱讀時間:6 分鐘
查看 Tahsin Masrur 的個人資料
Tahsin Masrur 軟體工程師

現代相機應用程式的特色在於強大且重疊的功能。使用者期望能錄製出色的 HDR 影片、以 60 FPS 捕捉流暢動作,並透過預覽畫面穩定功能取得極致流暢的影片,而且通常希望這些功能可以同時運作。

但開發人員都知道,實際情況更為複雜。如何保證特定裝置確實支援指定組合?過去,啟用多項功能往往像是一場賭博。您可以檢查個別功能支援,但合併這些功能可能會導致未定義的行為,或更糟的是,相機會話群組失敗。這種不確定性迫使開發人員採取保守做法,導致使用者無法在支援的裝置上獲得最佳體驗。

舉例來說,只有極少數的高階裝置能同時穩定支援 HDR 和 60 FPS 影片。因此,大多數應用程式會避免同時啟用這兩項功能,以免在多數手機上造成不佳的使用者體驗。

為解決這個問題,我們推出了 CameraX 中的 Feature Group,這個新 API 可消除這類不確定性。現在,您可以在設定相機之前,查詢是否支援特定功能組合,或直接告訴 CameraX 您的優先順序,讓 CameraX 為您啟用支援度最佳的組合。

CameraX 新手

在深入探討新的 Feature Group API 之前,我們先快速回顧一下 CameraX。CameraX 是 Jetpack 支援程式庫,旨在協助應用程式開發人員輕鬆開發相機應用程式。並提供一致且易於使用的 API 介面,適用於大多數 Android 裝置,具備 Android 6.0 (API 級別 23) 的回溯相容性。如果您是第一次使用 CameraX,建議您參閱官方說明文件,並試用程式碼實驗室,瞭解如何開始使用。

Feature Group API 的用途

您不必再賭運氣,可以放心提供最佳相機體驗,例如在支援的硬體 (如 Pixel 10 Pro) 上同時啟用 HDR 和 60 FPS 影片,同時在不支援該組合的裝置上,也能妥善避免錯誤。

unnamed.png
Pixel 10 Pro 同時啟用 HDR 和 60 FPS
unnamed (1).png
在無法同時執行 HDR 和 60 FPS 的舊裝置上,系統只會啟用 HDR,並停用 60 FPS 選項。

您可以使用 Feature Group API 執行下列操作:

  • 建構更聰明的動態 UI:根據即時硬體支援,智慧啟用或停用 UI 設定。舉例來說,如果使用者啟用 HDR,但裝置不支援 HDR 和 60 FPS 的組合,您可以立即將 60 FPS 選項設為灰色並停用。
hdr.gif
  • 提供可靠的「高畫質」模式: 設定相機時,優先列出所需功能。CameraX 會自動找出並啟用任何裝置最支援的組合,確保能獲得良好結果,不必使用複雜的裝置專屬邏輯。
  • 避免相機會話群組失敗:事先驗證支援情形,可避免相機嘗試設定不支援的組合,消除常見的當機原因,並提供流暢的使用者體驗。

運作方式:核心元件

新 API 的核心是 SessionConfig 和 CameraInfo 的重要新增功能。

  1. GroupableFeature:這個 API 導入一組預先定義的可分組功能,例如 HDR_HLG10、FPS_60、PREVIEW_STABILIZATION 和 IMAGE_ULTRA_HDR。由於運算限制,只有一組特定特徵可以與這個 API 提供的高度可靠性分組。我們正積極擴充這份清單,並會在日後推出的版本中支援更多功能。
  2. 新的 SessionConfig 參數:這個類別用於啟動相機工作階段,現在可接受兩個新參數:
    • requiredFeatureGroup:如果功能必須支援才能成功設定,請使用這個值。這適合使用者明確啟用的功能,例如切換「HDR」開關。為確保體驗確定且一致,如果要求的組合不受支援,bindToLifecycle 呼叫會擲回 IllegalArgumentException,而不是在不顯示任何訊息的情況下忽略功能要求。請事先使用 CameraInfo#isFeatureGroupSupported API (詳情請見下文) 查詢這項結果。
    • preferredFeatureGroup:如果功能並非必要,但建議使用,請使用這個值,例如您想實作預設的「高畫質」模式。您只要提供所需功能清單,並依優先順序排列,CameraX 就會自動啟用裝置支援的最高優先順序組合。
  3. CameraInfo#isFeatureGroupSupported():這是核心查詢方法,可明確檢查是否支援功能群組,非常適合在應用程式 UI 中,只向使用者提供支援的功能選項。您傳遞 SessionConfig,它會傳回布林值,指出是否支援該組合。如果您打算將 SessionConfig 與必要功能繫結,請先使用這個 API,確保系統支援該功能。

實際導入

接下來,我們來看看如何使用這些元件,打造更優質的相機體驗。

情境 1:「盡可能」高畫質模式

如要預設啟用最佳功能,可以向 preferredFeatureGroup 提供優先順序清單。在這個範例中,我們指示 CameraX 優先處理 HDR,接著是 60 FPS,最後是預覽畫面防震功能。CameraX 會處理複雜的檢查作業,檢查所有可能的組合,並選擇裝置支援的最佳組合。

舉例來說,如果裝置可以同時處理 HDR 和 60 FPS,但無法同時處理預覽畫面防震功能,CameraX 就會啟用前兩項功能,並捨棄第三項。這樣一來,您就能獲得最佳體驗,不必編寫複雜的裝置專屬檢查。

cameraProvider.bindToLifecycle(

    lifecycleOwner,

    cameraSelector,

    SessionConfig(

        useCases = listOf(preview, videoCapture),

        // The order of features in this list determines their priority. 

        // CameraX will enable the best-supported combination based on these

        // priorities: HDR_HLG10 > FPS_60 > Preview Stabilization.  

        preferredFeatureGroup =

           listOf(HDR_HLG10, FPS_60, PREVIEW_STABILIZATION),

    ).apply {

        // (Optional) Get a callback with the enabled features

        // to update your UI. 

        setFeatureSelectionListener { selectedFeatures ->

            updateUiIndicators(selectedFeatures)

        }

    }

)

在這個程式碼片段中,CameraX 會嘗試按照下列優先順序啟用功能組合,並選取裝置完全支援的第一個組合:

  1. HDR + 60 FPS + 預覽防震功能
  2. HDR + 60 FPS
  3. HDR + 預覽防震功能
  4. 高動態範圍
  5. 60 FPS + 預覽防震功能
  6. 每秒 60 個影格
  7. 預覽防震功能
  8. 以上皆非

情境 2:建構回應式 UI

如要建立可回應使用者選項,並防止使用者選取不支援功能組合的使用者介面,您可以直接查詢支援。以下函式會檢查哪些功能與使用者「目前」選取的項目不相容,以便停用對應的 UI 元素。

/**

 * Returns a list of features that are NOT supported in combination

 * with the currently selected features.

 */

fun getUnsupportedFeatures(

    currentFeatures: Set<GroupableFeature>

): Set<GroupableFeature> {

    val unsupportedFeatures = mutableSetOf<GroupableFeature>()

    val appFeatureOptions = setOf(HDR_HLG10, FPS_60, PREVIEW_STABILIZATION)


    // Iterate over every available feature option in your app. 

    appFeatureOptions.forEach { featureOption ->

        // Skip features the user has already selected. 

        if (currentFeatures.contains(featureOption)) return@forEach


        // Check if adding this new feature is supported. 

        val isSupported = cameraInfo.isFeatureGroupSupported(

            SessionConfig(

                useCases = useCases,

                // Check the new feature on top of existing ones.

                requiredFeatureGroup = currentFeatures + featureOption

            )

        )


        if (!isSupported) {

            unsupportedFeatures.add(featureOption)

        }

    }


    return unsupportedFeatures

}

接著,您可以將這項邏輯連結至 ViewModel 或 UI 控制器,以便回應使用者輸入內容,並使用保證可運作的設定重新繫結相機。

// Invoked when user turns some feature on/off.

fun onFeatureChange(currentFeatures: Set<GroupableFeature>) {

    // Identify features that are unsupported with the current selection.

    val unsupportedFeatures = getUnsupportedFeatures(currentFeatures)



    // Update app UI so that users can't enable them.

    updateDisabledFeatures(unsupportedFeatures)



    // Since the UI now only allows selecting supported feature combinations, 

    // `currentFeatures` is always valid. This allows setting

    // `requiredFeatureGroup` directly, without needing to re-check for

    // support or set a feature selection listener.  

    cameraProvider.bindToLifecycle(

        lifecycleOwner,

        cameraSelector,

        SessionConfig(

            useCases = listOf(preview, videoCapture),

            requiredFeatureGroup = currentFeatures,

        )

    )

}

如要在實際運作的應用程式中查看這些概念,可以探索我們的內部測試應用程式。該應用程式提供上述「盡力而為」和「反應式 UI」情境的完整實作。

請注意:這是測試應用程式,並非官方支援的範例。雖然這份文件是 Feature Group API 的絕佳參考資料,但尚未經過完善處理,不適合用於正式環境。

立即開始使用

Feature Group API 可消除使用進階相機功能時的模糊地帶。只要提供確定性的功能支援查詢方式,就能安心建構更強大可靠的相機應用程式。

這項 API 在 CameraX 1.5 中為實驗功能,預計在 1.6 版本中完全穩定,並將提供更多支援和改善。

詳情請參閱官方說明文件。我們期待看到你的精彩傑作,也歡迎你提供寶貴意見。歡迎透過下列管道分享你的想法或回報任何問題:

繼續閱讀