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

דוחות של קומפיילר Compose
הקומפיילר של Compose יכול להפיק את התוצאות של הסקת היציבות שלו לבדיקה. בעזרת הפלט הזה, אתם יכולים לקבוע אילו פונקציות קומפוזביליות ניתנות לדילוג ואילו לא. בסעיפי המשנה הבאים מוסבר בקצרה איך להשתמש בדוחות האלה, אבל מידע מפורט יותר זמין במסמכי התיעוד הטכני.
הגדרה
דוחות הקומפיילר של Compose לא מופעלים כברירת מחדל. אפשר להפעיל אותן באמצעות דגל קומפיילר. ההגדרה המדויקת משתנה בהתאם לפרויקט, אבל בפרויקטים שמשתמשים בפלאגין Gradle של Compose Compiler, אפשר להוסיף את הקוד הבא בקובץ build.gradle של כל מודול.
android { ... }
composeCompiler {
reportsDestination = layout.buildDirectory.dir("compose_compiler")
metricsDestination = layout.buildDirectory.dir("compose_compiler")
}
עכשיו, כשיוצרים את הפרויקט, נוצרים דוחות של Compose compiler.
פלט לדוגמה
ה-reportsDestination מוציא שלושה קבצים. הפלט הבא הוא דוגמה מ-JetSnack.
-
<modulename>-classes.txt: דוח על היציבות של המחלקות במודול הזה. דוגמה. -
<modulename>-composables.txt: דוח על האפשרות להפעיל מחדש ולדלג על הפונקציות הניתנות לשילוב במודול. דגימה. -
<modulename>-composables.csv:גרסתCSVשל דוח הפונקציות הניתנות לשילוב, שאפשר לייבא לגיליון אלקטרוני או לעבד באמצעות סקריפט. דוגמה
דוח Composables
הקובץ composables.txt מפרט כל פונקציה קומפוזבילית במודול הנתון, כולל היציבות של הפרמטרים שלה, ואם אפשר להפעיל אותה מחדש או לדלג עליה. הנה תרחיש לדוגמה מ-JetSnack:
restartable skippable scheme("[androidx.compose.ui.UiComposable]") fun SnackCollection(
stable snackCollection: SnackCollection
stable onSnackClick: Function1<Long, Unit>
stable modifier: Modifier? = @static Companion
stable index: Int = @static 0
stable highlight: Boolean = @static true
)
בדוגמה הזו, כל פרמטר של SnackCollection מסומן כ-stable, ולכן Compose משווה בין כל הפרמטרים באמצעות שוויון מבני (Object.equals()). הפרמטרים של stable הם אידיאליים לערכים פרימיטיביים ולמחלקות נתונים קטנות ושטוחות עם בדיקות .equals() זולות, אבל אם מאלצים מודלים שמכילים אוספים (כמו SnackCollection שעוטף List<Snack>) להיות stable, Compose קורא ל-.equals() בכל פריט בכל קומפוזיציה מחדש. כשהאפשרות Strong skipping mode מופעלת, עדיף לשמור מודלים שמכילים אוספים unstable כדי ש-Compose ישווה ביניהם באמצעות שוויון מופעים (===).
לחלופין, נבחן דוגמה אחרת שנוצרה כשמצב דילוג חזק מושבת:
restartable scheme("[androidx.compose.ui.UiComposable]") fun HighlightedSnacks(
stable index: Int
unstable snacks: List<Snack>
stable onSnackClick: Function1<Long, Unit>
stable modifier: Modifier? = @static Companion
)
כשהמצב Strong Skipping מושבת (לפני Kotlin 2.0.20), אי אפשר לדלג על הפונקציה הניתנת לקישור HighlightedSnacks – Compose אף פעם לא מדלג עליה במהלך הרכבה מחדש, גם אם אף אחד מהפרמטרים שלה לא השתנה, בגלל הפרמטר unstable snacks.
כאשר מצב דילוג חזק מופעל (ברירת המחדל ב-Kotlin 2.0.20 ואילך), HighlightedSnacks מסומן כ-skippable, ו-Compose משווה את הפרמטר unstable snacks באמצעות שוויון מופעים (===). כתוצאה מכך, Compose מדלג על HighlightedSnacks אם מועברת אותה הפניה ל-List, ויוצר אותו מחדש רק אם מועבר מופע List שהוקצה לאחרונה.
הדוח "כיתות"
הקובץ classes.txt מכיל דוח דומה על המחלקות במודול הנתון. קטע הקוד הבא הוא הפלט של הכיתה Snack:
unstable class Snack {
stable val id: Long
stable val name: String
stable val imageUrl: String
stable val price: Long
stable val tagline: String
unstable val tags: Set<String>
<runtime stability> = Unstable
}
לעיון, זו ההגדרה של Snack:
data class Snack(
val id: Long,
val name: String,
val imageUrl: String,
val price: Long,
val tagline: String = "",
val tags: Set<String> = emptySet()
)
הקומפיילר של Compose סימן את Snack כלא יציב. הסיבה לכך היא שסוג הפרמטר tags הוא Set<String>. זהו סוג שלא ניתן לשינוי, בהנחה שהוא לא MutableSet. עם זאת, מחלקות אוסף סטנדרטיות כמו Set, List ו-Map הן בסופו של דבר ממשקים. לכן, יכול להיות שההטמעה הבסיסית עדיין ניתנת לשינוי.
לדוגמה, אפשר לכתוב val set: Set<String> = mutableSetOf("foo"). המשתנה הוא קבוע והסוג המוצהר שלו לא ניתן לשינוי, אבל ההטמעה שלו עדיין ניתנת לשינוי. הקומפיילר של Compose לא יכול להיות בטוח שהמחלקה הזו לא ניתנת לשינוי, כי הוא רואה רק את הסוג המוצהר. לכן, הוא מסמן את tags כלא יציב.