วินิจฉัยปัญหาด้านความเสถียร

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

เครื่องมือตรวจสอบเลย์เอาต์

เครื่องมือตรวจสอบเลย์เอาต์ใน 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 ว่าไม่เสถียร