מצב דילוג חזק

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

הפעלת מצב דילוג חזק

דילוג חזק מופעל כברירת מחדל ב-Kotlin 2.0.20.

כדי להפעיל דילוג חזק על מודול Gradle בגרסה שקדמה ל-2.0.20, צריך לכלול את האפשרות הבאה בבלוק composeCompiler של הגדרת Gradle:

android { ... }

composeCompiler {
   enableStrongSkippingMode = true
}

אפשרות דילוג קומפוזיציונית

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

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

מתי כדאי לדלג

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

  • השוואה של פרמטרים לא יציבים באמצעות שוויון בין שתי מכונות (===)
  • השוואה של פרמטרים יציבים מתבצעת באמצעות בדיקת שוויון בין אובייקטים (Object.equals())

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

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

@NonSkippableComposable
@Composable
fun MyNonSkippableComposable {}

הוספת הערות לכיתות ככיתות יציבות

אם רוצים אובייקט שמשתמש בשוויון אובייקטים במקום בשוויון אירועים, ממשיכים להוסיף הערה לכיתה הנתונה באמצעות @Stable. דוגמה למקרה שבו יכול להיות שתצטרכו לעשות זאת היא כשאתם צופים ברשימת אובייקטים שלמה. מקורות נתונים כמו Room מקצים אובייקטים חדשים לכל פריט ברשימה בכל פעם שאחד מהם משתנה.

שימוש בזיכרון לטווח ארוך (memoization) ב-Lambda

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

דוגמאות

כדי לבצע שמירת מידע של פונקציות lambda בתוך רכיבים מורכבים כשמשתמשים ב-strong skipping, המהדר עוטף את הפונקציה lambda בקריאה ל-remember. המפתח שלו הוא התמונות של הלמה.

נניח שיש לכם פונקציית lambda כמו בדוגמה הבאה:

@Composable
fun MyComposable(unstableObject: Unstable, stableObject: Stable) {
    val lambda = {
        use(unstableObject)
        use(stableObject)
    }
}

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

@Composable
fun MyComposable(unstableObject: Unstable, stableObject: Stable) {
    val lambda = remember(unstableObject, stableObject) {
        {
            use(unstableObject)
            use(stableObject)
        }
    }
}

המפתחות פועלים לפי אותם כללי השוואה שפועלים בפונקציות הניתנות ליצירה. סביבת זמן הריצה משווה בין מפתחות לא יציבים באמצעות שוויון בין מכונות. הוא משווה בין מפתחות יציבים באמצעות שוויון אובייקטים.

שימוש בזיכרון לטווח קצר (Memoization) ושינוי של הרכב

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

הימנעות מ-memoization

אם יש לכם פונקציית lambda שאתם לא רוצים לשמור במטמון, תוכלו להשתמש בהערה @DontMemoize.

val lambda = @DontMemoize {
    ...
}

גודל ה-APK

כשמפעילים הידור, רכיבי Composable שניתן לדלג עליהם יוצרים יותר קוד מאשר רכיבי Composable שלא ניתן לדלג עליהם. כשהאפשרות 'דילוג חזק' מופעלת, המהדר מתייג כמעט את כל הרכיבים הניתנים לקישור כרכיבים שניתן לדלג עליהם, ומעביר את כל פונקציות ה-lambda ל-remember{...}. לכן, הפעלת מצב דילוג חזק משפיעה במידה קטנה מאוד על גודל ה-APK של האפליקציה.

הפעלת דילוג חזק ב-Now In Android הגדילה את גודל ה-APK ב-4KB. ההבדל בגודל תלוי במידה רבה במספר הרכיבים הניתנים לשילוב שלא ניתן היה לדלג עליהם בעבר באפליקציה הנתונה, אבל הוא אמור להיות קטן יחסית.