חדשות על מוצרים

מעבר לתכונות בודדות: שילוב תכונות מובטח עם CameraX 1.5

משך הקריאה: 6 דקות
צפייה בפרופיל של Tahsin Masrur
Tahsin Masrur מהנדס תוכנה

אפליקציות מצלמה מודרניות מוגדרות על ידי תכונות חזקות שחופפות זו לזו. המשתמשים מצפים להקלטת סרטונים באיכות HDR מדהימה, ללכידת תנועה חלקה בקצב של 60 פריימים לשנייה (FPS) ולקבלת צילומים חלקים במיוחד באמצעות התכונה 'ייצוב בתצוגה מקדימה' – ולעתים קרובות, כל אלה בו-זמנית.

אנחנו מפתחים, ולכן ברור לנו שהמציאות מורכבת יותר. איך אפשר להבטיח שמכשיר מסוים תומך בשילוב נתון? עד עכשיו, הפעלת כמה תכונות הייתה לרוב הימור. אפשר לבדוק אם יש תמיכה בכל תכונה בנפרד, אבל שילוב של כמה תכונות עלול להוביל להתנהגות לא מוגדרת או, גרוע מכך, לסשן מצלמה שנכשל.  חוסר הוודאות הזה מאלץ את המפתחים להיות שמרנים, ומונע ממשתמשים במכשירים מתאימים ליהנות מהחוויה הטובה ביותר שאפשר.

לדוגמה, רק מעט מכשירי פרימיום תומכים בווידאו עם HDR ו-60 FPS בו-זמנית. לכן, ברוב האפליקציות לא מפעילים את שתי האפשרויות בו-זמנית כדי למנוע חוויית משתמש גרועה ברוב הטלפונים.

כדי לפתור את הבעיה הזו, אנחנו משיקים את Feature Group ב-CameraX – API חדש שנועד לבטל את הניחושים האלה. עכשיו אפשר לשאול אם שילוב ספציפי של תכונות נתמך לפני שמגדירים את המצלמה, או פשוט להגדיר ל-CameraX את סדר העדיפויות ולתת לה להפעיל את השילוב הנתמך הכי טוב בשבילכם.

למשתמשים חדשים ב-CameraX

לפני שנעמיק ב-API החדש של קבוצת התכונות, נסכם בקצרה מה זה CameraX. ‏CameraX היא ספריית תמיכה של Jetpack, שנועדה לעזור לכם לפתח אפליקציות מצלמה בקלות רבה יותר. הוא מספק ממשק API עקבי וקל לשימוש שפועל ברוב מכשירי Android, עם תאימות לדורות קודמים של Android 6.0 (רמת API‏ 23). אם אתם חדשים ב-CameraX, מומלץ לעיין בתיעוד הרשמי ולנסות את ה-codelab כדי להתחיל.

מה אפשר לבנות באמצעות Feature Group API

אתם לא צריכים יותר לנחש אילו שילובים של תכונות יפעלו, ויכולים לספק בביטחון את חוויית המצלמה הטובה ביותר האפשרית – כמו וידאו HDR ו-60 FPS בו-זמנית בחומרה מתאימה (למשל, Pixel 10 Pro) – תוך הימנעות מטעויות במכשירים שלא תומכים בשילוב.

unnamed.png
Pixel 10 Pro עם HDR ו-60 FPS בו-זמנית
unnamed (1).png
במכשיר ישן יותר שבו אי אפשר להפעיל בו-זמנית HDR ו-60 FPS, רק HDR מופעל והאפשרות 60 FPS מושבתת.

באמצעות Feature Group API, אתם יכולים:

  • בניית ממשקי משתמש דינמיים וחכמים יותר: הפעלה או השבתה חכמה של הגדרות בממשק המשתמש על סמך תמיכה בחומרה בזמן אמת. לדוגמה, אם משתמש מפעיל HDR, אתם יכולים להשבית את האפשרות של 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 תגרום להקפצת הודעת שגיאה (throw) IllegalArgumentException אם השילוב המבוקש לא אפשרי, במקום להתעלם בשקט מהגשת בקשה להוספת תכונה. מומלץ להשתמש ב-API של CameraInfo#isFeatureGroupSupported (פרטים בהמשך) כדי לשלוח שאילתה לגבי התוצאה הזו מראש.
    • ‫preferredFeatureGroup: משתמשים בזה לתכונות רצויות אבל אופציונליות, לדוגמה כשרוצים להטמיע מצב ברירת מחדל של 'איכות גבוהה'. אתם מספקים רשימה של התכונות הרצויות מסודרת לפי סדר העדיפויות שלכם, ו-CameraX מפעילה באופן אוטומטי את השילוב בעדיפות הגבוהה ביותר שהמכשיר תומך בו.
  3. ‫CameraInfo#isFeatureGroupSupported()‎: זוהי שיטת השאילתה העיקרית לבדיקה מפורשת אם קבוצת תכונות נתמכת. היא מתאימה במיוחד להצגת אפשרויות של תכונות נתמכות בלבד למשתמשים בממשק המשתמש של האפליקציה. מעבירים אליו 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. HDR
  5. ‫60 FPS + ייצוב תמונה בתצוגה מקדימה
  6. 60 FPS
  7. תצוגה מקדימה של ייצוב
  8. אף אחת מהתכונות שלמעלה

תרחיש 2: בניית ממשק משתמש רספונסיבי

כדי ליצור ממשק משתמש שמגיב לבחירות של המשתמשים ומונע מהם לבחור שילוב של תכונות שלא נתמכות, אפשר לשלוח שאילתה ישירות כדי לבדוק אם יש תמיכה. הפונקציה שבהמשך בודקת אילו תכונות לא תואמות לבחירות הנוכחיות של המשתמש, וכך מאפשרת לכם להשבית את רכיבי ממשק המשתמש המתאימים.

/**

 * 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 או לבקר ממשק המשתמש כדי להגיב לקלט של המשתמשים ולקשר מחדש את המצלמה עם הגדרה מובטחת.

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

        )

    )

}

כדי לראות את המושגים האלה באפליקציה פעילה, אפשר לעיין באפליקציית הבדיקה הפנימית שלנו. היא מספקת הטמעה מלאה של שני התרחישים שצוינו למעלה: 'המאמץ הטוב ביותר' ו'ממשק משתמש תגובתי'.

הערה: זוהי אפליקציית בדיקה ולא דוגמה רשמית נתמכת. הוא יכול לשמש כנקודת התייחסות מצוינת ל-Feature Group API, אבל הוא לא מותאם לשימוש בסביבת ייצור.

מתחילים עוד היום

ה-API של קבוצת התכונות מסיר את העמימות שקיימת בעבודה עם יכולות מתקדמות של המצלמה. התכונה הזו מספקת דרך דטרמיניסטית לשאילתות לגבי תמיכה בתכונות, כך שתוכלו ליצור אפליקציות מצלמה חזקות ואמינות יותר בביטחון.

ה-API זמין כניסיוני ב-CameraX 1.5, והוא צפוי להיות יציב לחלוטין בגרסה 1.6, עם תמיכה ושיפורים נוספים בדרך.

מידע נוסף מופיע במסמכי התיעוד הרשמיים. אנחנו כבר ממש סקרנים לראות מה תיצרו, ונשמח לקבל מכם משוב. נשמח לקבל ממך משוב ולדווח על בעיות באמצעות הערוצים הבאים:

נכתב על ידי:
להמשך קריאה