Wiadomości o usługach

Poza pojedynczymi funkcjami: gwarantowanie kombinacji funkcji w CameraX 1.5

Czas czytania: 6 minut
Tahsin Masrur
Inżynier oprogramowania

Nowoczesne aplikacje do obsługi aparatu mają wiele zaawansowanych funkcji, które się wzajemnie uzupełniają. Użytkownicy oczekują, że będą mogli nagrywać filmy w oszałamiającym trybie HDR, rejestrować płynne ruchy w 60 klatkach na sekundę i uzyskiwać płynne materiały dzięki stabilizacji podglądu – często jednocześnie.

Jako deweloperzy wiemy, że rzeczywistość jest bardziej skomplikowana. Jak możesz mieć pewność, że dane urządzenie obsługuje daną kombinację? Do tej pory włączanie wielu funkcji często było ryzykowne. Możesz sprawdzić obsługę poszczególnych funkcji, ale ich połączenie może prowadzić do niezdefiniowanego zachowania lub, co gorsza, do nieudanej sesji kamery. Ta niepewność zmusza deweloperów do zachowawczości, co uniemożliwia użytkownikom korzystającym z wydajnych urządzeń uzyskanie najlepszych możliwych wrażeń.

Na przykład bardzo niewiele urządzeń premium obsługuje jednocześnie HDR i filmy z 60 klatkami na sekundę. Dlatego większość aplikacji unika włączania obu tych funkcji jednocześnie, aby zapobiec pogorszeniu komfortu użytkowania na większości telefonów.

Aby rozwiązać ten problem, wprowadzamy grupę funkcji w CameraX – nowy interfejs API, który eliminuje zgadywanie. Możesz teraz sprawdzić, czy określona kombinacja funkcji jest obsługiwana przed skonfigurowaniem aparatu, lub po prostu poinformować CameraX o swoich priorytetach i pozwolić jej włączyć najlepiej obsługiwaną kombinację.

Dla osób, które dopiero zaczynają korzystać z CameraX

Zanim przejdziemy do nowego interfejsu Feature Group API, przypomnijmy sobie, czym jest CameraX. CameraX to biblioteka pomocy Jetpack, która ułatwia tworzenie aplikacji aparatu. Zapewnia spójny i łatwy w użyciu interfejs API, który działa na większości urządzeń z Androidem i jest wstecznie zgodny z Androidem 6.0 (poziom interfejsu API 23). Jeśli dopiero zaczynasz korzystać z CameraX, zapoznaj się z oficjalną dokumentacją i wypróbuj codelab.

Co możesz tworzyć za pomocą interfejsu Feature Group API

Nie musisz już ryzykować, łącząc różne funkcje. Możesz mieć pewność, że zapewnisz najlepsze możliwe wrażenia podczas korzystania z aparatu, np. nagrywanie filmów w HDR i 60 kl./s na odpowiednim sprzęcie (np. Pixel 10 Pro), a jednocześnie unikniesz błędów na urządzeniach, które nie obsługują takiego połączenia.

unnamed.png

Pixel 10 Pro z włączonymi jednocześnie trybami HDR i 60 klatek na sekundę

unnamed (1).png

Na starszych urządzeniach, na których nie można jednocześnie korzystać z HDR i 60 kl./s, włączona jest tylko technologia HDR, a opcja 60 kl./s jest wyłączona.

Za pomocą interfejsu Feature Group API możesz:

  • Twórz inteligentniejsze, dynamiczne interfejsy: inteligentnie włączaj i wyłączaj ustawienia w interfejsie na podstawie obsługi sprzętu w czasie rzeczywistym. Jeśli na przykład użytkownik włączy HDR, możesz natychmiast wyszarzyć i wyłączyć opcję 60 kl./s, jeśli ta kombinacja nie jest obsługiwana na danym urządzeniu. 
unsupported-features-disabled.gif
  • Zapewnij niezawodny tryb „Wysoka jakość”:  skonfiguruj kamerę, korzystając z listy priorytetowych funkcji. CameraX automatycznie wyszukuje i włącza najlepiej obsługiwaną kombinację dla danego urządzenia, zapewniając świetny efekt bez złożonej logiki specyficznej dla urządzenia.
  • Zapobieganie niepowodzeniom sesji aparatu: dzięki wcześniejszemu sprawdzeniu obsługi zapobiegasz próbom skonfigurowania przez aparat nieobsługiwanej kombinacji, co eliminuje częste źródło awarii i zapewnia płynne działanie.

Jak to działa: podstawowe komponenty

Nowy interfejs API koncentruje się na kluczowych dodatkach do klas SessionConfigCameraInfo.

  1. GroupableFeature: ten interfejs API wprowadza zestaw predefiniowanych funkcji, które można grupować, takich jak HDR_HLG10FPS_60, PREVIEW_STABILIZATION i IMAGE_ULTRA_HDR. Ze względu na ograniczenia obliczeniowe tylko określony zestaw funkcji można pogrupować z wysokim stopniem niezawodności, jaki zapewnia ten interfejs API. Pracujemy nad rozszerzeniem tej listy i w przyszłych wersjach wprowadzimy obsługę kolejnych funkcji.
     
  2. Nowe parametry SessionConfig: ta klasa, używana do rozpoczynania sesji aparatu, akceptuje teraz 2 nowe parametry:
    • requiredFeatureGroup: używaj tej wartości w przypadku funkcji, które muszą być obsługiwane, aby konfiguracja się powiodła. Jest to idealne rozwiązanie w przypadku funkcji, które użytkownik włącza wprost, np. przełącznika „HDR”. Aby zapewnić deterministyczne i spójne działanie, wywołanie bindToLifecycle zgłosi wyjątek IllegalArgumentException, jeśli żądana kombinacja nie jest obsługiwana, zamiast cicho ignorować prośbę o dodanie funkcji. Aby wcześniej sprawdzić ten wynik, użyj interfejsu CameraInfo#isFeatureGroupSupported API (szczegóły poniżej).
    • preferredFeatureGroup: używaj tego ustawienia w przypadku funkcji, które są pożądane, ale opcjonalne, np. gdy chcesz wdrożyć domyślny tryb „Wysoka jakość”. Podajesz listę wybranych funkcji uporządkowaną według priorytetów, a CameraX automatycznie włącza kombinację o najwyższym priorytecie, którą obsługuje urządzenie.
  3. CameraInfo#isFeatureGroupSupported(): to podstawowa metoda sprawdzania, czy grupa funkcji jest obsługiwana. Jest ona odpowiednia do udostępniania użytkownikom w interfejsie aplikacji tylko obsługiwanych opcji funkcji. Przekazujesz do niego wartość SessionConfig, a on zwraca wartość logiczną wskazującą, czy ta kombinacja jest obsługiwana. Jeśli zamierzasz powiązać SessionConfig z wymaganymi funkcjami, najpierw użyj tego interfejsu API, aby sprawdzić, czy jest on obsługiwany. 

Wdrażanie w praktyce

Przyjrzyjmy się, jak wykorzystać te komponenty, aby poprawić jakość zdjęć.

Scenariusz 1. Tryb wysokiej jakości „najlepsze możliwe wyniki”

Jeśli chcesz domyślnie włączać najlepsze funkcje, możesz przekazać do preferredFeatureGroup listę uszeregowaną według priorytetu. W tym przykładzie informujemy CameraX, aby priorytetowo traktował HDR, następnie 60 kl./s, a na końcu stabilizację podglądu. CameraX zajmuje się złożonością sprawdzania wszystkich możliwych kombinacji i wybierania najlepszej, którą obsługuje urządzenie.

Jeśli na przykład urządzenie obsługuje HDR i 60 kl./s, ale nie stabilizację podglądu, CameraX włączy pierwsze 2 funkcje i odrzuci trzecią. Dzięki temu możesz zapewnić użytkownikom jak najlepsze wrażenia bez pisania skomplikowanych testów dla poszczególnych urządzeń.

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)

        }

    }

)

W przypadku tego fragmentu kodu CameraX spróbuje włączyć kombinacje funkcji w tej kolejności priorytetów, wybierając pierwszą, która jest w pełni obsługiwana przez urządzenie:

  1. HDR + 60 kl./s + stabilizacja podglądu
  2. HDR + 60 kl./s
  3. Stabilizacja podglądu HDR+
  4. HDR
  5. 60 kl./s + stabilizacja podglądu
  6. 60 kl./s
  7. Podgląd stabilizacji
  8. Żadna z powyższych funkcji

Scenariusz 2. Tworzenie reaktywnego interfejsu

Aby utworzyć interfejs, który reaguje na wybory użytkownika i uniemożliwia mu wybranie nieobsługiwanej kombinacji funkcji, możesz bezpośrednio wysyłać zapytania o obsługę. Funkcja poniżej sprawdza, które funkcje są niezgodne z bieżącymi wyborami użytkownika, co pozwala wyłączyć odpowiednie elementy interfejsu.

/**

 * 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

}

Następnie możesz połączyć tę logikę z elementem ViewModel lub kontrolerem interfejsu, aby reagować na dane wejściowe użytkownika i ponownie powiązać kamerę z konfiguracją, która na pewno będzie działać.

// 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,

        )

    )

}

Aby zobaczyć te koncepcje w działającej aplikacji, możesz zapoznać się z naszą wewnętrzną aplikacją testową. Zawiera ona pełną implementację obu opisanych powyżej scenariuszy „najlepsze wyniki” i „reaktywny interfejs”.

Uwaga: jest to aplikacja testowa, a nie oficjalnie obsługiwany przykład. Jest to świetny materiał referencyjny dotyczący interfejsu Feature Group API, ale nie został on dopracowany pod kątem użytku produkcyjnego.

Zacznij już dziś

Interfejs Feature Group API usuwa niejednoznaczność związaną z korzystaniem z zaawansowanych funkcji aparatu. Dzięki deterministycznemu sposobowi sprawdzania obsługi funkcji możesz tworzyć bardziej zaawansowane i niezawodne aplikacje aparatu.

Interfejs API jest dostępny w wersji eksperymentalnej w CameraX 1.5, a w wersji 1.6 ma stać się w pełni stabilny. W przyszłości planujemy wprowadzić więcej funkcji i ulepszeń.

Więcej informacji znajdziesz w oficjalnej dokumentacji. Nie możemy się doczekać Twoich kreacji i opinii. Podziel się wrażeniami i zgłoś wszelkie problemy, korzystając z tych kanałów:

Autor:

Czytaj dalej