Compose จะพิจารณาว่าประเภทต่างๆ มีความเสถียรหรือไม่เสถียร ประเภทจะเสถียรหากไม่สามารถเปลี่ยนแปลงได้ หรือหาก Compose สามารถทราบได้ว่าค่าของประเภทนั้นมีการเปลี่ยนแปลงระหว่างการจัดองค์ประกอบใหม่หรือไม่ ประเภทจะไม่เสถียรหาก Compose ไม่ทราบว่าค่าของประเภทมีการเปลี่ยนแปลงระหว่างการจัดองค์ประกอบใหม่หรือไม่
Compose ใช้ความเสถียรของพารามิเตอร์ของ Composable เพื่อกำหนดวิธีเปรียบเทียบอินพุตและตัดสินใจว่าจะข้าม Composable ในระหว่างการจัดองค์ประกอบใหม่ได้หรือไม่ (โดยเปิดใช้โหมดการข้ามที่เข้มงวดโดยค่าเริ่มต้นตั้งแต่ Kotlin 2.0.20 เป็นต้นไป)
- พารามิเตอร์ที่เสถียร: Compose จะเปรียบเทียบพารามิเตอร์ที่เสถียรโดยใช้ความเท่าเทียมกันเชิงโครงสร้าง (
Object.equals()) หากพารามิเตอร์ที่เสถียรของ Composable เท่ากับค่าก่อนหน้า Compose จะข้ามพารามิเตอร์นั้น - พารามิเตอร์ที่ไม่เสถียร: เมื่อเปิดใช้โหมดการข้ามที่เข้มงวด (ค่าเริ่มต้นใน Kotlin 2.0.20 ขึ้นไป) Compose จะเปรียบเทียบพารามิเตอร์ที่ไม่เสถียรโดยใช้ความเท่าเทียมกันของอินสแตนซ์ (
===) และข้าม Composable หากมีการส่งอินสแตนซ์ออบเจ็กต์เดียวกัน ในเวอร์ชันก่อน Kotlin 2.0.20 (หรือเมื่อปิดใช้โหมดการข้ามที่เข้มงวด) Compose จะจัดองค์ประกอบ Composable ที่มีพารามิเตอร์ที่ไม่เสถียรใหม่เสมอเมื่อองค์ประกอบหลักจัดองค์ประกอบใหม่
หากแอปของคุณจัดสรรอินสแตนซ์ใหม่ของพารามิเตอร์ที่ไม่เสถียรบ่อยครั้ง หรือบังคับให้มีการตรวจสอบ .equals() ที่มีค่าใช้จ่ายสูงในคอลเล็กชันขนาดใหญ่โดยการใส่คำอธิบายประกอบโมเดลมากเกินไป คุณอาจพบการจัดองค์ประกอบใหม่หรือโอเวอร์เฮดการเปรียบเทียบที่ไม่จำเป็น
เอกสารนี้แสดงรายละเอียดเกี่ยวกับวิธีที่ Compose กำหนดความเสถียรและวิธีเพิ่มประสิทธิภาพเพื่อปรับปรุงประสิทธิภาพและประสบการณ์ของผู้ใช้โดยรวม
ออบเจ็กต์ที่เปลี่ยนแปลงไม่ได้
ข้อมูลโค้ดต่อไปนี้แสดงหลักการทั่วไปเบื้องหลังความเสถียรและการจัดองค์ประกอบใหม่
คลาส Contact เป็นคลาสข้อมูลที่เปลี่ยนแปลงไม่ได้ เนื่องจากพารามิเตอร์ทั้งหมดเป็นค่าพื้นฐานที่กำหนดด้วยคีย์เวิร์ด val เมื่อสร้างอินสแตนซ์ของ Contact แล้ว คุณจะเปลี่ยนค่าของพร็อพเพอร์ตี้ของออบเจ็กต์ไม่ได้
หากพยายามทำเช่นนั้น คุณจะสร้างออบเจ็กต์ใหม่
data class Contact(val name: String, val number: String)
คอมโพสิเบิล ContactRow มีพารามิเตอร์ประเภท Contact
@Composable
fun ContactRow(contact: Contact, modifier: Modifier = Modifier) {
var selected by remember { mutableStateOf(false) }
Row(modifier) {
ContactDetails(contact)
ToggleButton(selected, onToggled = { selected = !selected })
}
}
พิจารณาสิ่งที่จะเกิดขึ้นเมื่อผู้ใช้คลิกปุ่มเปิด/ปิดและสถานะ selected เปลี่ยนไป
- Compose จะประเมินว่าควรจัดองค์ประกอบโค้ดภายใน
ContactRowใหม่หรือไม่ - โดยจะเห็นว่าอาร์กิวเมนต์เดียวสำหรับ
ContactDetailsเป็นประเภทContact - เนื่องจาก
Contactเป็นคลาสข้อมูลที่เปลี่ยนแปลงไม่ได้ Compose จึงมั่นใจว่าไม่มีอาร์กิวเมนต์ใดของContactDetailsมีการเปลี่ยนแปลง - ด้วยเหตุนี้ Compose จึงข้าม
ContactDetailsและไม่จัดองค์ประกอบใหม่ - ในทางกลับกัน อาร์กิวเมนต์สำหรับ
ToggleButtonมีการเปลี่ยนแปลง และ Compose จะจัดองค์ประกอบคอมโพเนนต์นั้นใหม่
ออบเจ็กต์ที่เปลี่ยนแปลงได้
แม้ว่าตัวอย่างก่อนหน้านี้จะใช้ออบเจ็กต์ที่เปลี่ยนแปลงไม่ได้ แต่คุณก็สร้างออบเจ็กต์ที่เปลี่ยนแปลงได้ ลองพิจารณาข้อมูลโค้ดต่อไปนี้
data class Contact(var name: String, var number: String)
เนื่องจากพารามิเตอร์แต่ละรายการของ Contact เป็น var แล้ว คลาสจึงไม่เปลี่ยนแปลงอีกต่อไป
หากพร็อพเพอร์ตี้มีการเปลี่ยนแปลง Compose จะไม่รับรู้ เนื่องจาก Compose จะติดตามการเปลี่ยนแปลงในออบเจ็กต์ State ของ Compose เท่านั้น
Compose จะถือว่าคลาสนี้ไม่เสถียร เมื่อใช้โหมดการข้ามที่เข้มงวด (Kotlin 2.0.20 ขึ้นไป) Compose จะเปรียบเทียบ Contact โดยใช้ความเท่ากันของอินสแตนซ์ (===) กล่าวคือ การเปลี่ยนแปลง contact.name ในตำแหน่งจะไม่ทริกเกอร์การจัดองค์ประกอบใหม่ ในขณะที่การส่งอินสแตนซ์ Contact ที่จัดสรรใหม่ซึ่งมีค่าเหมือนกันจะยังคงบังคับให้ ContactDetails จัดองค์ประกอบใหม่ (และหากไม่มีโหมดการข้ามที่เข้มงวด ContactDetails จะจัดองค์ประกอบใหม่ทุกครั้งที่ selected มีการเปลี่ยนแปลง)
การใช้งานใน Compose
การพิจารณาว่า Compose กำหนดฟังก์ชันที่จะข้ามระหว่างการจัดองค์ประกอบใหม่อย่างไรนั้นอาจเป็นประโยชน์ แต่ก็ไม่ได้สำคัญมากนัก
เมื่อคอมไพเลอร์ Compose ทำงานกับโค้ดของคุณ ระบบจะทำเครื่องหมายแต่ละฟังก์ชันและประเภทด้วยแท็กอย่างน้อย 1 แท็ก แท็กเหล่านี้แสดงให้เห็นว่า Compose จัดการฟังก์ชันหรือประเภทอย่างไรในระหว่างการจัดองค์ประกอบใหม่
ฟังก์ชัน
Compose สามารถทำเครื่องหมายฟังก์ชันเป็น skippable หรือ restartable ได้ โปรดทราบว่าระบบอาจทำเครื่องหมายฟังก์ชันเป็นอย่างใดอย่างหนึ่ง ทั้ง 2 อย่าง หรือไม่ทำเครื่องหมายเลย ดังนี้
- ข้ามได้: หากคอมไพเลอร์ทำเครื่องหมาย Composable ว่าข้ามได้ Compose จะข้าม Composable นั้นในระหว่างการจัดองค์ประกอบใหม่ได้หากอาร์กิวเมนต์ทั้งหมดเท่ากับค่าก่อนหน้า (เมื่อใช้โหมดการข้ามที่เข้มงวดใน Kotlin 2.0.20 ขึ้นไป คอมโพสิเบิลที่รีสตาร์ทได้ทั้งหมดจะข้ามได้โดยอัตโนมัติ)
- รีสตาร์ทได้: Composable ที่รีสตาร์ทได้จะทำหน้าที่เป็น "ขอบเขต" ที่การจัดองค์ประกอบใหม่สามารถเริ่มต้นได้ กล่าวคือ ฟังก์ชันนี้อาจเป็นจุดเริ่มต้นที่ Compose สามารถเริ่มเรียกใช้โค้ดอีกครั้งเพื่อจัดองค์ประกอบใหม่หลังจากการเปลี่ยนแปลงสถานะ
ประเภท
Compose จะทำเครื่องหมายประเภทเป็นแบบเปลี่ยนแปลงไม่ได้หรือแบบเสถียร โดยแต่ละประเภทจะมีลักษณะอย่างใดอย่างหนึ่งต่อไปนี้
- ไม่เปลี่ยนรูป: Compose จะทำเครื่องหมายประเภทเป็นไม่เปลี่ยนรูปหากค่าของพร็อพเพอร์ตี้ไม่สามารถเปลี่ยนแปลงได้ และเมธอดทั้งหมดมีความโปร่งใสในการอ้างอิง
- โปรดทราบว่าประเภทพื้นฐานทั้งหมดจะทำเครื่องหมายเป็นแบบเปลี่ยนแปลงไม่ได้ ซึ่งได้แก่
String,IntและFloat
- โปรดทราบว่าประเภทพื้นฐานทั้งหมดจะทำเครื่องหมายเป็นแบบเปลี่ยนแปลงไม่ได้ ซึ่งได้แก่
- เสถียร: บ่งบอกถึงประเภทที่พร็อพเพอร์ตี้สามารถเปลี่ยนแปลงได้หลังจากการสร้าง หากพร็อพเพอร์ตี้เหล่านั้นเปลี่ยนแปลงระหว่างรันไทม์ Compose จะรับรู้ถึงการเปลี่ยนแปลงเหล่านั้น
แก้ไขข้อบกพร่องเกี่ยวกับความเสถียร
หากแอปกำลังจัดองค์ประกอบใหม่ให้กับ Composable ที่พารามิเตอร์ไม่มีการเปลี่ยนแปลง ให้ตรวจสอบก่อนว่ามีการจัดสรรอินสแตนซ์ใหม่ของประเภทที่ไม่เสถียรในการจัดองค์ประกอบใหม่ทุกครั้งหรือไม่ (หรือหากปิดใช้โหมดการข้ามที่เข้มงวด ให้ตรวจสอบว่า Composable มีพารามิเตอร์ที่มีพร็อพเพอร์ตี้ var หรือพร็อพเพอร์ตี้ val ของประเภทที่ไม่เสถียรหรือไม่)
ดูข้อมูลโดยละเอียดเกี่ยวกับวิธีวิเคราะห์ปัญหาที่ซับซ้อนเกี่ยวกับความเสถียรใน Compose ได้ที่คู่มือแก้ไขข้อบกพร่องด้านความเสถียร
แก้ปัญหาด้านความเสถียร
ดูข้อมูลเกี่ยวกับวิธีทำให้การใช้งาน Compose มีความเสถียรได้ที่คู่มือแก้ไขปัญหาด้านความเสถียร
สรุป
โดยรวมแล้ว คุณควรทราบประเด็นต่อไปนี้
- พารามิเตอร์: Compose จะกำหนดความเสถียรของพารามิเตอร์แต่ละรายการของ Composable เพื่อตัดสินใจว่าจะเปรียบเทียบพารามิเตอร์เหล่านั้นโดยใช้ความเท่าเทียมกันเชิงโครงสร้าง (
.equals()) หรือความเท่าเทียมกันของอินสแตนซ์ (===) ในระหว่างการจัดองค์ประกอบใหม่หรือไม่ - การแก้ไขทันที: หากสังเกตเห็นว่าระบบไม่ได้ข้าม Composable และทำให้เกิดปัญหาด้านประสิทธิภาพ ให้ตรวจสอบว่ามีการสร้างอินสแตนซ์ใหม่ของพารามิเตอร์ที่ไม่เสถียรขึ้นมาใหม่ในแต่ละรอบหรือไม่ หรือมีการใช้พร็อพเพอร์ตี้
varแทนStateหรือไม่ - รายงานคอมไพเลอร์: คุณสามารถใช้รายงานคอมไพเลอร์เพื่อพิจารณาว่ามีการอนุมานความเสถียรใดเกี่ยวกับคลาสของคุณ
- คอลเล็กชัน: Compose ถือว่าอินเทอร์เฟซคอลเล็กชันมาตรฐาน (
List,SetและMap) ไม่เสถียรเนื่องจากการติดตั้งใช้งานที่เกี่ยวข้องอาจเปลี่ยนแปลงได้ เมื่อใช้โหมดการข้ามที่เข้มงวด (เปิดใช้โดยค่าเริ่มต้นใน Kotlin 2.0.20 ขึ้นไป) คอลเล็กชันที่ไม่เสถียรจะยังคงข้ามการจัดองค์ประกอบใหม่โดยใช้ความเท่ากันของอินสแตนซ์ (===) เมื่อการอ้างอิงคอลเล็กชันไม่เปลี่ยนแปลง โปรดระมัดระวังในการแทนที่คอลเล็กชันมาตรฐานด้วยคอลเล็กชันที่เปลี่ยนแปลงไม่ได้ของ Kotlinx หรือการใส่คำอธิบายประกอบคลาสที่เก็บคอลเล็กชันด้วย@Immutableหรือ@Stableเนื่องจากการเปรียบเทียบทุกองค์ประกอบกับ.equals()ในการส่งผ่านการจัดองค์ประกอบใหม่แต่ละครั้งอาจมีค่าใช้จ่ายสูงกว่าการจัดองค์ประกอบใหม่เอง - โมดูลอื่นๆ: Compose จะพิจารณาคลาสจากโมดูลที่คอมไพเลอร์ Compose ไม่ทำงานว่าไม่เสถียร (เปรียบเทียบโดยใช้
===ภายใต้โหมดการข้ามแบบเข้มงวด) หากแหล่งข้อมูลสร้างอินสแตนซ์โมเดลขนาดเล็กแบบแบนซ้ำๆ จากโมดูลที่ไม่ใช่ Compose ที่มีค่าเหมือนกัน คุณสามารถกำหนดค่าไฟล์การกำหนดค่าความเสถียรหรือใช้@Stableหรือ@Immutableโดยที่.equals()มีค่าใช้จ่ายต่ำ
อ่านเพิ่มเติม
- ประสิทธิภาพ: ดูเคล็ดลับการแก้ไขข้อบกพร่องเพิ่มเติมเกี่ยวกับประสิทธิภาพของ Compose ได้ที่คู่มือแนวทางปฏิบัติแนะนำและการพูดคุยเกี่ยวกับ I/O