產品新訊

超越單一功能:使用 CameraX 1.5 確保功能組合

6 分鐘小故事
Tahsin Masrur
軟體工程師

現代相機應用程式的特色是功能強大且重疊。使用者希望錄製令人驚豔的 HDR 影片、以 60 每秒影格數拍攝流暢的動態,並透過預覽畫面穩定功能取得流暢的影片片段,而且通常希望同時達成這些目標。

身為開發人員,我們知道實際情況更加複雜。如何確保特定裝置確實支援特定組合?到目前為止,啟用多項功能通常是碰運氣。您可以檢查個別功能是否支援,但結合這些功能可能會導致未定義的行為,或更糟的是,導致攝影機工作階段失敗。這種不確定性迫使開發人員採取保守做法,導致有能力的裝置無法為使用者提供最佳體驗。

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

為解決這個問題,我們推出了 CameraX 中的功能群組,這項新 API 的設計宗旨是消除這類猜測。現在您可以在設定相機,查詢是否支援特定功能組合,也可以直接告知 CameraX 您的優先順序,讓 CameraX 為您啟用最適合的組合。

CameraX 新手

在深入瞭解新的 Feature Group API 之前,讓我們先快速回顧 CameraX 的用途。CameraX 是 Jetpack 支援程式庫,可協助您輕鬆開發相機應用程式。這個程式庫提供一致且易於使用的 API 介面,適用於大多數 Android 裝置,並可回溯相容於 Android 6.0 (API 級別 23)。如果您是 CameraX 新手,建議先參閱官方文件,並試試 Codelab

您可以使用特徵群組 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,但裝置不支援該組合,您可以立即將 60 FPS 選項設為灰色並停用。
unsupported-features-disabled.gif
  • 提供可靠的「高品質」模式: 設定攝影機時,請優先列出所需功能。CameraX 會自動找出並啟用最適合特定裝置的組合,確保產生優質結果,無需複雜的裝置專屬邏輯。
  • 避免相機工作階段失敗:預先驗證支援項目,可防止相機嘗試設定不支援的組合,消除常見的當機原因,提供流暢的使用者體驗。

運作方式:核心元件

新版 API 的核心是 SessionConfigCameraInfo 的重要新增項目。

  1. GroupableFeature:這項 API 推出一組預先定義的可分組功能,例如 HDR_HLG10FPS_60PREVIEW_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,並防止使用者選取不支援的功能組合,您可以直接查詢支援項目。下方函式會檢查哪些功能與使用者的目前選取項目不相容,方便您停用對應的 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 版中全面穩定推出,並持續提供更多支援和改善項目。

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

繼續閱讀