หากพบปัญหาด้านประสิทธิภาพที่เกิดจากการจัดองค์ประกอบใหม่โดยไม่จำเป็นหรือมากเกินไป คุณควรแก้ไขข้อบกพร่องด้านความเสถียรของแอป คู่มือนี้จะอธิบายวิธีการต่างๆ ในการดำเนินการดังกล่าว
เครื่องมือตรวจสอบเลย์เอาต์
เครื่องมือตรวจสอบเลย์เอาต์ใน Android Studio ช่วยให้คุณเห็นว่าคอมโพสิเบิลใดกำลังจัดองค์ประกอบใหม่ในแอป โดยจะแสดงจำนวนครั้งที่ Compose จัดองค์ประกอบใหม่หรือข้ามคอมโพเนนต์

รายงานคอมไพเลอร์ Compose
คอมไพเลอร์ Compose สามารถแสดงผลลัพธ์ของการอนุมานความเสถียรเพื่อตรวจสอบได้ เมื่อใช้เอาต์พุตนี้ คุณจะระบุได้ว่า Composable ใดข้ามได้และข้ามไม่ได้ ส่วนย่อยต่อไปนี้จะสรุปวิธีใช้รายงานเหล่านี้ แต่หากต้องการข้อมูลโดยละเอียดเพิ่มเติม โปรดดูเอกสารทางเทคนิค
ตั้งค่า
รายงานคอมไพเลอร์ Compose ไม่ได้เปิดใช้โดยค่าเริ่มต้น คุณเปิดใช้งานได้ด้วยแฟล็กคอมไพเลอร์ การตั้งค่าที่แน่นอนจะแตกต่างกันไปตามโปรเจ็กต์ แต่สำหรับโปรเจ็กต์ที่ใช้ปลั๊กอิน Gradle ของคอมไพเลอร์ Compose คุณสามารถเพิ่มข้อมูลต่อไปนี้ในไฟล์ build.gradle ของแต่ละโมดูลได้
android { ... }
composeCompiler {
reportsDestination = layout.buildDirectory.dir("compose_compiler")
metricsDestination = layout.buildDirectory.dir("compose_compiler")
}
ตอนนี้ระบบจะสร้างรายงานคอมไพเลอร์ Compose เมื่อสร้างโปรเจ็กต์
ตัวอย่างเอาต์พุต
reportsDestination จะแสดงผลไฟล์ 3 ไฟล์ ต่อไปนี้เป็นตัวอย่างเอาต์พุตจาก JetSnack
<modulename>-classes.txt: รายงานเกี่ยวกับความเสถียรของคลาสในโมดูลนี้ ตัวอย่าง<modulename>-composables.txt: รายงานเกี่ยวกับความสามารถในการรีสตาร์ทและข้ามได้ของ Composable ในโมดูล ตัวอย่าง<modulename>-composables.csv:รายงาน Composable เวอร์ชันCSVที่คุณนำเข้าสเปรดชีตหรือประมวลผลโดยใช้สคริปต์ได้ ตัวอย่าง
รายงาน Composable
ไฟล์ 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() ในแต่ละรายการในการจัดองค์ประกอบใหม่ทุกครั้ง เมื่อเปิดใช้โหมดข้ามแบบเข้มงวด การเก็บโมเดลที่มีคอลเล็กชัน 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
)
เมื่อปิดใช้โหมดการข้ามที่เข้มงวด (ก่อน 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 ว่าไม่เสถียร