Jetpack Compose เป็นชุดเครื่องมือ UI สมัยใหม่ที่อธิบายอย่างชัดเจนสำหรับ Android Compose ช่วยให้การเขียนและดูแลรักษา UI ของแอปง่ายขึ้นด้วยการจัดเตรียม API แบบประกาศที่ช่วยให้คุณแสดงผล UI ของแอปได้โดยไม่ต้องเปลี่ยนมุมมองฟรอนท์เอนด์แบบบังคับ คำศัพท์นี้ต้องมีการอธิบายเพิ่มเติม แต่ความหมายนั้นสำคัญต่อการออกแบบแอปของคุณ
กระบวนทัศน์การเขียนโปรแกรมแบบประกาศ
ในอดีต ลำดับชั้นการแสดงผลของ Android สามารถแสดงเป็นโครงสร้างต้นไม้ของวิดเจ็ต UI เมื่อสถานะของแอปเปลี่ยนแปลงเนื่องจากสิ่งต่างๆ เช่น การโต้ตอบของผู้ใช้ คุณต้องอัปเดตลําดับชั้น UI เพื่อแสดงข้อมูลปัจจุบัน
วิธีที่พบบ่อยที่สุดในการอัปเดต UI คือการเดินผ่านแผนผังโดยใช้ฟังก์ชันต่างๆ เช่น findViewById() และเปลี่ยนโหนดโดยเรียกใช้เมธอดต่างๆ เช่น button.setText(String), container.addChild(View) หรือ img.setImageBitmap(Bitmap) เมธอดเหล่านี้จะเปลี่ยนสถานะภายในของวิดเจ็ต
การจัดการมุมมองด้วยตนเองจะเพิ่มโอกาสที่จะเกิดข้อผิดพลาด หากมีการแสดงผลข้อมูลในหลายตำแหน่ง คุณอาจลืมอัปเดตมุมมองใดมุมมองหนึ่งที่แสดงข้อมูลนั้น นอกจากนี้ยังอาจทำให้เกิดสถานะที่ผิดกฎหมายเมื่อการอัปเดต 2 รายการขัดแย้งกันในลักษณะที่ไม่คาดคิด เช่น การอัปเดตอาจพยายามตั้งค่าโหนดที่เพิ่งนำออกจาก UI โดยทั่วไป ความซับซ้อนในการบำรุงรักษาซอฟต์แวร์จะเพิ่มขึ้นตามจำนวนมุมมองที่ต้องอัปเดต
ในช่วงหลายปีที่ผ่านมา อุตสาหกรรมทั้งหมดได้เริ่มเปลี่ยนไปใช้โมเดล UI แบบประกาศ ซึ่งช่วยลดความซับซ้อนในการสร้างและอัปเดตอินเทอร์เฟซผู้ใช้
เทคนิคนี้ทำงานโดยการสร้างทั้งหน้าจอใหม่ตั้งแต่ต้นในเชิงแนวคิด จากนั้นจึงใช้เฉพาะการเปลี่ยนแปลงที่จำเป็น วิธีนี้ช่วยหลีกเลี่ยงความซับซ้อนของการอัปเดตลำดับชั้นการแสดงผลแบบเก็บสถานะด้วยตนเอง Compose เป็นเฟรมเวิร์ก UI แบบประกาศ
ความท้าทายอย่างหนึ่งในการสร้างทั้งหน้าจอใหม่คืออาจมีค่าใช้จ่ายสูงในแง่ของเวลา พลังการประมวลผล และการใช้งานแบตเตอรี่ เพื่อลดต้นทุนนี้ Compose จะเลือกส่วนของ UI ที่ต้องวาดใหม่ ณ เวลาใดเวลาหนึ่งอย่างชาญฉลาด ซึ่งจะส่งผลต่อวิธีออกแบบคอมโพเนนต์ UI ตามที่อธิบายไว้ในการจัดองค์ประกอบใหม่
ตัวอย่างฟังก์ชันที่ประกอบกันได้
เมื่อใช้ Compose คุณจะสร้างอินเทอร์เฟซผู้ใช้ได้โดยกำหนดชุดฟังก์ชันที่ประกอบกันได้ซึ่งรับข้อมูลและแสดงองค์ประกอบ UI ตัวอย่างเช่น วิดเจ็ต Greeting ซึ่งรับ String และแสดงวิดเจ็ต Text ที่แสดงข้อความทักทาย
สิ่งที่ควรทราบเกี่ยวกับฟังก์ชันนี้มีดังนี้
- คำอธิบายประกอบ: ฟังก์ชันจะมีคำอธิบายประกอบ
@Composableฟังก์ชันที่ประกอบกันได้ทั้งหมดต้องมีคำอธิบายประกอบนี้ คำอธิบายประกอบนี้จะแจ้งให้คอมไพเลอร์ Compose ทราบว่าฟังก์ชันนี้มีไว้เพื่อแปลงข้อมูลเป็น UI - อินพุตข้อมูล: ฟังก์ชันจะรับข้อมูล ฟังก์ชันที่ประกอบกันได้สามารถรับพารามิเตอร์ ซึ่งช่วยให้ตรรกะของแอปอธิบาย UI ได้ ในกรณีนี้ วิดเจ็ตของเราจะยอมรับ
Stringเพื่อให้สามารถทักทายผู้ใช้ด้วยชื่อได้ - การแสดงผล UI: ฟังก์ชันจะแสดงข้อความใน UI โดยจะเรียกใช้ฟังก์ชันที่ประกอบกันได้ที่ชื่อ
Text()ซึ่งจะสร้างองค์ประกอบ UI ของข้อความขึ้นมาจริงๆ ฟังก์ชันที่ประกอบกันได้จะแสดงลำดับชั้นของ UI โดยการเรียกใช้ฟังก์ชันที่ประกอบกันได้อื่นๆ - ไม่มีค่าที่แสดงผล: ฟังก์ชันจะไม่แสดงผลใดๆ ฟังก์ชัน Compose ที่แสดง UI ไม่จำเป็นต้องแสดงผลใดๆ เนื่องจากฟังก์ชันเหล่านี้อธิบายสถานะหน้าจอเป้าหมายแทนการสร้างวิดเจ็ต UI
คุณสมบัติ: ฟังก์ชันนี้ทำงานรวดเร็ว ไม่เปลี่ยนแปลงผลลัพธ์ และไม่มีผลข้างเคียง
- ฟังก์ชันจะทำงานเหมือนเดิมเมื่อเรียกใช้หลายครั้งด้วยอาร์กิวเมนต์เดียวกัน และจะไม่ใช้ค่าอื่นๆ เช่น ตัวแปรส่วนกลางหรือการเรียกใช้
random() - ฟังก์ชันนี้จะอธิบาย UI โดยไม่มีผลข้างเคียง เช่น การแก้ไขพร็อพเพอร์ตี้หรือตัวแปรส่วนกลาง
โดยทั่วไปแล้ว ฟังก์ชันที่ประกอบกันได้ทั้งหมดต้องเขียนด้วยพร็อพเพอร์ตี้เหล่านี้ ด้วยเหตุผลที่อธิบายไว้ในการจัดองค์ประกอบใหม่
- ฟังก์ชันจะทำงานเหมือนเดิมเมื่อเรียกใช้หลายครั้งด้วยอาร์กิวเมนต์เดียวกัน และจะไม่ใช้ค่าอื่นๆ เช่น ตัวแปรส่วนกลางหรือการเรียกใช้
การเปลี่ยนกระบวนทัศน์แบบประกาศ
เมื่อใช้ชุดเครื่องมือ UI แบบเชิงวัตถุที่จำเป็นจำนวนมาก คุณจะเริ่มต้น UI โดยสร้างอินสแตนซ์ของต้นไม้วิดเจ็ต ซึ่งมักจะทำได้โดยการขยายไฟล์เลย์เอาต์ XML วิดเจ็ตแต่ละรายการจะรักษาสถานะภายในของตนเอง และแสดงเมธอด Getter และ Setter ที่ช่วยให้ตรรกะของแอปโต้ตอบกับวิดเจ็ตได้
ในแนวทางการประกาศของ Compose วิดเจ็ตจะไม่มีสถานะและไม่แสดงฟังก์ชัน Setter หรือ Getter ที่จริงแล้ว วิดเจ็ตจะไม่แสดงเป็นออบเจ็กต์
คุณอัปเดต UI โดยเรียกใช้ฟังก์ชันที่ประกอบกันได้เดียวกันโดยมีอาร์กิวเมนต์ต่างกัน ซึ่งจะช่วยลดความซับซ้อนในการระบุสถานะให้กับรูปแบบสถาปัตยกรรม เช่น ViewModel ตามที่อธิบายไว้ในคู่มือสถาปัตยกรรมแอป จากนั้น Composable จะมีหน้าที่เปลี่ยนสถานะปัจจุบันของแอปพลิเคชันเป็น UI ทุกครั้งที่ข้อมูลที่สังเกตได้อัปเดต
เมื่อผู้ใช้โต้ตอบกับ UI แล้ว UI จะแสดงเหตุการณ์ต่างๆ เช่น onClick
เหตุการณ์เหล่านั้นควรแจ้งตรรกะของแอป ซึ่งจะเปลี่ยนสถานะของแอปได้
เมื่อสถานะเปลี่ยนแปลง ระบบจะเรียกใช้ฟังก์ชันที่ประกอบกันได้อีกครั้งพร้อมข้อมูลใหม่ ซึ่งจะทำให้ระบบวาดองค์ประกอบ UI ใหม่ กระบวนการนี้เรียกว่าการจัดองค์ประกอบใหม่
เนื้อหาแบบไดนามิก
เนื่องจากฟังก์ชันที่ประกอบกันได้เขียนขึ้นใน Kotlin แทน XML จึงสามารถเป็นแบบไดนามิกได้เหมือนกับโค้ด Kotlin อื่นๆ ตัวอย่างเช่น สมมติว่าคุณต้องการสร้าง UI ที่ทักทายรายชื่อผู้ใช้
@Composable fun Greeting(names: List<String>) { for (name in names) { Text("Hello $name") } }
ฟังก์ชันนี้จะรับรายชื่อและสร้างคำทักทายสำหรับผู้ใช้แต่ละราย
ฟังก์ชันที่ประกอบกันได้อาจมีความซับซ้อนมาก คุณสามารถใช้คำสั่ง if เพื่อตัดสินใจว่าต้องการแสดงองค์ประกอบ UI ที่เฉพาะเจาะจงหรือไม่ คุณสามารถใช้ลูปได้ คุณสามารถเรียกใช้ฟังก์ชันตัวช่วยได้ คุณจะมีความยืดหยุ่นอย่างเต็มที่ในภาษาที่ใช้
ประสิทธิภาพและความยืดหยุ่นนี้เป็นข้อดีหลักอย่างหนึ่งของ Jetpack Compose
การจัดองค์ประกอบใหม่
ในโมเดล UI แบบบังคับ หากต้องการเปลี่ยนวิดเจ็ต คุณต้องเรียกใช้ Setter ในวิดเจ็ตเพื่อเปลี่ยนสถานะภายใน ใน Compose คุณจะเรียกใช้ฟังก์ชันที่ประกอบกันได้อีกครั้งด้วยข้อมูลใหม่ การดำเนินการนี้จะทำให้ฟังก์ชันจัดองค์ประกอบใหม่ โดยวิดเจ็ตที่ฟังก์ชันแสดงจะได้รับการวาดใหม่ด้วยข้อมูลใหม่หากจำเป็น เฟรมเวิร์ก Compose สามารถจัดองค์ประกอบใหม่เฉพาะคอมโพเนนต์ที่มีการเปลี่ยนแปลงได้อย่างชาญฉลาด
ตัวอย่างเช่น ลองพิจารณาฟังก์ชันที่ประกอบกันได้ซึ่งแสดงปุ่มต่อไปนี้
@Composable fun ClickCounter(clicks: Int, onClick: () -> Unit) { Button(onClick = onClick) { Text("I've been clicked $clicks times") } }
ทุกครั้งที่มีการคลิกปุ่ม ผู้เรียกจะอัปเดตค่าของ clicks
Compose จะเรียกใช้ Lambda ด้วยฟังก์ชัน Text อีกครั้งเพื่อแสดงค่าใหม่ กระบวนการนี้เรียกว่าการจัดองค์ประกอบใหม่ ส่วนฟังก์ชันอื่นๆ ที่ไม่ได้ขึ้นอยู่กับค่าดังกล่าวจะไม่ได้รับการจัดองค์ประกอบใหม่
ดังที่ได้กล่าวไปแล้ว การจัดองค์ประกอบต้นไม้ UI ทั้งหมดใหม่อาจใช้ทรัพยากรในการประมวลผลสูง ซึ่งจะใช้พลังการประมวลผลและอายุการใช้งานแบตเตอรี่ Compose แก้ปัญหานี้ด้วยการจัดองค์ประกอบใหม่อัจฉริยะ
การจัดองค์ประกอบใหม่คือกระบวนการเรียกใช้ฟังก์ชันที่ประกอบกันได้อีกครั้งเมื่ออินพุตมีการเปลี่ยนแปลง เมื่อ Compose จัดองค์ประกอบใหม่ตามอินพุตใหม่ ระบบจะเรียกใช้เฉพาะฟังก์ชันหรือ Lambda ที่อาจมีการเปลี่ยนแปลง และข้ามส่วนที่เหลือ Compose จะจัดองค์ประกอบใหม่ได้อย่างมีประสิทธิภาพโดยข้ามฟังก์ชันหรือ Lambda ที่มีพารามิเตอร์ที่ไม่มีการเปลี่ยนแปลง
อย่าพึ่งพาผลข้างเคียงจากการเรียกใช้ฟังก์ชันที่ประกอบกันได้ เนื่องจากระบบอาจข้ามการจัดองค์ประกอบใหม่ของฟังก์ชัน หากทำเช่นนั้น ผู้ใช้อาจพบพฤติกรรมที่แปลกประหลาดและคาดเดาไม่ได้ในแอปของคุณ ผลข้างเคียงคือการเปลี่ยนแปลงใดๆ ที่แอปส่วนที่เหลือมองเห็นได้ ตัวอย่างเช่น การดำเนินการต่อไปนี้เป็นผลข้างเคียงที่เป็นอันตรายทั้งหมด
- การเขียนไปยังพร็อพเพอร์ตี้ของออบเจ็กต์ที่แชร์
- กำลังอัปเดตออบเจ็กต์ที่สังเกตได้ใน
ViewModel - กำลังอัปเดตค่ากำหนดที่ใช้ร่วมกัน
ระบบอาจเรียกใช้ฟังก์ชันที่ประกอบกันได้ซ้ำบ่อยครั้งในทุกเฟรม เช่น เมื่อมีการแสดงผลภาพเคลื่อนไหว ฟังก์ชันที่ประกอบกันได้ควรทำงานอย่างรวดเร็วเพื่อหลีกเลี่ยงการกระตุกระหว่างภาพเคลื่อนไหว หากต้องการดำเนินการที่มีค่าใช้จ่ายสูง เช่น การอ่านจากค่ากำหนดที่ใช้ร่วมกัน ให้ดำเนินการในโครูทีนในเบื้องหลังและส่งผลลัพธ์ของค่าไปยังฟังก์ชันที่ประกอบกันได้เป็นพารามิเตอร์
ตัวอย่างเช่น โค้ดนี้จะสร้าง Composable เพื่ออัปเดตค่าใน SharedPreferences Composable ไม่ควรอ่านหรือเขียนจากค่ากำหนดที่ใช้ร่วมกันเอง แต่โค้ดนี้จะย้ายการอ่านและเขียนไปยัง ViewModel ใน Coroutine เบื้องหลังแทน ตรรกะของแอปจะส่งค่าปัจจุบันพร้อม Callback เพื่อทริกเกอร์การอัปเดต
@Composable fun SharedPrefsToggle( text: String, value: Boolean, onValueChanged: (Boolean) -> Unit ) { Row { Text(text) Checkbox(checked = value, onCheckedChange = onValueChanged) } }
เอกสารนี้กล่าวถึงสิ่งต่างๆ ที่ควรทราบเมื่อใช้ Compose ดังนี้
- การจัดองค์ประกอบใหม่จะข้ามฟังก์ชันที่ประกอบกันได้และ Lambda ให้มากที่สุดเท่าที่จะเป็นไปได้
- การจัดองค์ประกอบใหม่เป็นแบบมองโลกในแง่ดีและอาจถูกยกเลิกได้
- ระบบอาจเรียกใช้ฟังก์ชันที่ประกอบกันได้ค่อนข้างบ่อย โดยอาจเรียกใช้ทุกเฟรมของภาพเคลื่อนไหว
- ฟังก์ชันที่ประกอบกันได้สามารถทำงานพร้อมกันได้
- ฟังก์ชันที่ประกอบกันได้สามารถทำงานในลำดับใดก็ได้
ส่วนต่อไปนี้จะอธิบายวิธีสร้างฟังก์ชันที่ประกอบกันได้เพื่อรองรับการจัดองค์ประกอบใหม่ ไม่ว่าในกรณีใด แนวทางปฏิบัติแนะนำคือการทำให้ฟังก์ชันที่ประกอบกันได้ทำงานอย่างรวดเร็ว ไม่เปลี่ยนแปลง และไม่มีผลข้างเคียง
การจัดองค์ประกอบใหม่จะข้ามให้มากที่สุดเท่าที่จะเป็นไปได้
เมื่อ UI บางส่วนไม่ถูกต้อง Compose จะพยายามอย่างเต็มที่เพื่อจัดองค์ประกอบใหม่เฉพาะส่วนที่ต้องอัปเดต ซึ่งหมายความว่าระบบอาจข้ามไปเรียกใช้คอมโพสิเบิลของ Button รายการเดียวอีกครั้งโดยไม่ต้องเรียกใช้คอมโพสิเบิลที่สูงกว่าหรือต่ำกว่าในแผนผัง UI
ฟังก์ชันที่ประกอบกันได้และ Lambda ทุกรายการอาจจัดองค์ประกอบใหม่ด้วยตัวเอง ตัวอย่างต่อไปนี้แสดงวิธีที่การจัดองค์ประกอบใหม่สามารถข้ามองค์ประกอบบางอย่างเมื่อแสดงผลรายการ
/** * Display a list of names the user can click with a header */ @Composable fun NamePicker( header: String, names: List<String>, onNameClicked: (String) -> Unit ) { Column { // this will recompose when [header] changes, but not when [names] changes Text(header, style = MaterialTheme.typography.bodyLarge) HorizontalDivider() // LazyColumn is the Compose version of a RecyclerView. // The lambda passed to items() is similar to a RecyclerView.ViewHolder. LazyColumn { items(names) { name -> // When an item's [name] updates, the adapter for that item // will recompose. This will not recompose when [header] changes NamePickerItem(name, onNameClicked) } } } } /** * Display a single name the user can click. */ @Composable private fun NamePickerItem(name: String, onClicked: (String) -> Unit) { Text(name, Modifier.clickable(onClick = { onClicked(name) })) }
ขอบเขตแต่ละรายการเหล่านี้อาจเป็นสิ่งเดียวที่ดำเนินการระหว่างการจัดองค์ประกอบใหม่
Compose อาจข้ามไปยัง Lambda Column โดยไม่เรียกใช้รายการหลักใดๆ เมื่อ header มีการเปลี่ยนแปลง และเมื่อเรียกใช้ Column Compose อาจเลือกข้ามรายการของ LazyColumn หาก names ไม่มีการเปลี่ยนแปลง
ขอย้ำอีกครั้งว่าฟังก์ชันที่ประกอบกันได้หรือแลมบ์ดาทั้งหมดควรไม่มีผลข้างเคียง เมื่อต้องการดำเนินการที่ส่งผลข้างเคียง ให้เรียกใช้จาก Callback
การจัดองค์ประกอบใหม่เป็นแบบมองในแง่ดี
การจัดองค์ประกอบใหม่จะเริ่มขึ้นเมื่อใดก็ตามที่ Compose คิดว่าพารามิเตอร์ของ Composable อาจมีการเปลี่ยนแปลง การจัดองค์ประกอบใหม่เป็นแบบมองโลกในแง่ดี ซึ่งหมายความว่า Compose คาดว่าจะจัดองค์ประกอบใหม่ให้เสร็จก่อนที่พารามิเตอร์จะเปลี่ยนแปลงอีกครั้ง หากพารามิเตอร์มีการเปลี่ยนแปลงก่อนที่การจัดองค์ประกอบใหม่จะเสร็จสิ้น Compose อาจยกเลิกการจัดองค์ประกอบใหม่และเริ่มใหม่ด้วยพารามิเตอร์ใหม่
เมื่อยกเลิกการจัดองค์ประกอบใหม่ Compose จะทิ้งแผนผัง UI จากการจัดองค์ประกอบใหม่ หากคุณมีผลข้างเคียงที่ขึ้นอยู่กับ UI ที่แสดง ผลข้างเคียงจะยังคงมีผลแม้ว่า Composition จะถูกยกเลิกก็ตาม ซึ่งอาจทำให้สถานะของแอปไม่สอดคล้องกัน
ยืนยันว่าฟังก์ชันที่ประกอบกันได้และ Lambda ทั้งหมดเป็นแบบ Idempotent และไม่มีผลข้างเคียงเพื่อจัดการกับการจัดองค์ประกอบใหม่ในเชิงบวก
ฟังก์ชันที่ประกอบกันได้อาจทำงานค่อนข้างบ่อย
ในบางกรณี ฟังก์ชันที่ประกอบกันได้อาจทำงานทุกเฟรมของภาพเคลื่อนไหว UI หากฟังก์ชันดำเนินการที่มีค่าใช้จ่ายสูง เช่น การอ่านจากพื้นที่เก็บข้อมูลของอุปกรณ์ ฟังก์ชันอาจทำให้ UI ขัดข้อง
ตัวอย่างเช่น หากวิดเจ็ตพยายามอ่านการตั้งค่าอุปกรณ์ วิดเจ็ตอาจอ่านการตั้งค่าเหล่านั้นหลายร้อยครั้งต่อวินาที ซึ่งส่งผลเสียต่อประสิทธิภาพของแอป
หากฟังก์ชันที่ประกอบกันได้ต้องการข้อมูล ให้กำหนดพารามิเตอร์สำหรับข้อมูลนั้น จากนั้นคุณสามารถย้ายงานที่ใช้ทรัพยากรมากไปยังเทรดอื่นนอก Composition และส่งค่าผลลัพธ์ไปยังฟังก์ชันที่ประกอบกันได้เป็นพารามิเตอร์โดยใช้ mutableStateOf หรือ LiveData
ฟังก์ชันที่ประกอบกันได้อาจทำงานพร้อมกันได้
Compose สามารถเพิ่มประสิทธิภาพการจัดองค์ประกอบใหม่ได้โดยเรียกใช้ฟังก์ชันที่ประกอบกันได้พร้อมกัน ซึ่งจะช่วยให้ Compose ใช้ประโยชน์จากหลายแกน และเรียกใช้ฟังก์ชันที่ประกอบกันได้ซึ่งไม่ได้อยู่บนหน้าจอโดยมีลำดับความสำคัญต่ำกว่า
การเพิ่มประสิทธิภาพนี้หมายความว่าฟังก์ชันที่ประกอบกันได้อาจทำงานภายในพูลของชุดข้อความในเบื้องหลัง
หากฟังก์ชันที่ประกอบกันได้เรียกใช้ฟังก์ชันใน ViewModel
Compose อาจเรียกใช้ฟังก์ชันนั้นจากหลายชุดข้อความพร้อมกัน
ฟังก์ชันที่ประกอบกันได้ทั้งหมดไม่ควรมีผลข้างเคียง เพื่อยืนยันว่าแอปพลิเคชันทำงานอย่างถูกต้อง แต่ให้ทริกเกอร์ผลข้างเคียงจาก Callback เช่น onClick ซึ่งจะทำงานในเธรด UI เสมอ
เมื่อมีการเรียกใช้ฟังก์ชันที่ประกอบกันได้ การเรียกใช้อาจเกิดขึ้นในเทรดที่แตกต่างจากผู้เรียก ซึ่งหมายความว่าควรหลีกเลี่ยงโค้ดที่แก้ไขตัวแปรในแลมบ์ดา Composable ทั้งเนื่องจากโค้ดดังกล่าวไม่ปลอดภัยต่อเทรด และเนื่องจากเป็นผลข้างเคียงที่ไม่อนุญาตของแลมบ์ดา Composable
ต่อไปนี้เป็นตัวอย่างที่แสดง Composable ซึ่งแสดงรายการและจำนวนรายการ
@Composable fun ListComposable(myList: List<String>) { Row(horizontalArrangement = Arrangement.SpaceBetween) { Column { for (item in myList) { Text("Item: $item") } } Text("Count: ${myList.size}") } }
โค้ดนี้ไม่มีผลข้างเคียง และแปลงรายการอินพุตเป็น UI โค้ดนี้เหมาะสำหรับการแสดงรายการขนาดเล็ก อย่างไรก็ตาม หากฟังก์ชันเขียนไปยังตัวแปรในเครื่อง โค้ดนี้จะไม่ปลอดภัยสำหรับเทรดหรือไม่ถูกต้อง
@Composable fun ListWithBug(myList: List<String>) { var items = 0 Row(horizontalArrangement = Arrangement.SpaceBetween) { Column { for (item in myList) { Card { Text("Item: $item") items++ // Avoid! Side-effect of the column recomposing. } } } Text("Count: $items") } }
ในตัวอย่างนี้ items จะได้รับการแก้ไขเมื่อมีการจัดองค์ประกอบใหม่ทุกครั้ง ซึ่งอาจเป็นทุกเฟรมของภาพเคลื่อนไหว หรือเมื่อรายการอัปเดต ไม่ว่าในกรณีใด UI จะแสดงจำนวนที่ไม่ถูกต้อง ด้วยเหตุนี้ Compose จึงไม่รองรับการเขียนลักษณะนี้ การห้ามเขียนลักษณะดังกล่าวช่วยให้เฟรมเวิร์กเปลี่ยนชุดข้อความเพื่อเรียกใช้ Lambda ที่ประกอบกันได้
ฟังก์ชันที่ประกอบกันได้สามารถทำงานในลำดับใดก็ได้
หากดูโค้ดของฟังก์ชันที่ประกอบกันได้ คุณอาจคิดว่าโค้ดจะทำงานตามลำดับที่ปรากฏ แต่ก็ไม่เสมอไป หากฟังก์ชันที่ประกอบกันได้มีการเรียกใช้ฟังก์ชันที่ประกอบกันได้อื่นๆ ฟังก์ชันเหล่านั้นอาจทำงานในลำดับใดก็ได้ Compose มีตัวเลือกในการจดจำว่าองค์ประกอบ UI บางอย่างมีลำดับความสำคัญสูงกว่าองค์ประกอบอื่นๆ และวาดองค์ประกอบเหล่านั้นก่อน
ตัวอย่างเช่น สมมติว่าคุณมีโค้ดลักษณะนี้เพื่อวาดหน้าจอ 3 หน้าจอในเลย์เอาต์แท็บ
@Composable fun ButtonRow() { MyFancyNavigation { StartScreen() MiddleScreen() EndScreen() } }
การเรียกใช้ StartScreen, MiddleScreen และ EndScreen อาจเกิดขึ้นในลำดับใดก็ได้ ซึ่งหมายความว่าคุณไม่สามารถตั้งค่าตัวแปรร่วม (ผลข้างเคียง) ใน StartScreen() และใช้ประโยชน์จากการเปลี่ยนแปลงนั้นใน MiddleScreen() ได้ แต่ฟังก์ชันแต่ละรายการจะต้องมีข้อมูลครบถ้วนในตัวเอง
ดูข้อมูลเพิ่มเติม
ดูข้อมูลเพิ่มเติมเกี่ยวกับวิธีคิดใน Compose และฟังก์ชันที่ประกอบกันได้ที่แหล่งข้อมูลเพิ่มเติมต่อไปนี้
วิดีโอ
แนะนำสำหรับคุณ
- หมายเหตุ: ข้อความลิงก์จะแสดงเมื่อ JavaScript ปิดอยู่
- Kotlin สำหรับ Jetpack Compose
- สถานะและ Jetpack Compose
- การวางเลเยอร์สถาปัตยกรรมของ Jetpack Compose