Jetpack Compose เป็นชุดเครื่องมือ UI แบบประกาศสิ่งที่ต้องการที่ทันสมัยสำหรับ Android Compose ช่วยให้คุณเขียนและดูแลรักษา UI ของแอปได้ง่ายขึ้นด้วย declarative 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 คุณจะสร้างอินเทอร์เฟซผู้ใช้ได้โดยกำหนดชุดฟังก์ชัน composable ที่รับข้อมูลและแสดงองค์ประกอบ UI ตัวอย่างง่ายๆ คือวิดเจ็ต Greeting
ซึ่งรับ String
และแสดงวิดเจ็ต Text
ที่แสดงข้อความทักทาย
รูปที่ 1 ฟังก์ชันคอมโพสิเบิลง่ายๆ ที่ส่งผ่านข้อมูลและใช้ข้อมูลดังกล่าวเพื่อแสดงผลวิดเจ็ตข้อความบนหน้าจอ
สิ่งที่ควรทราบเกี่ยวกับฟังก์ชันนี้มีดังนี้
ฟังก์ชันมีคำอธิบายประกอบ
@Composable
ฟังก์ชัน Composable ทั้งหมดต้องมีคำอธิบายประกอบนี้ คำอธิบายประกอบนี้จะแจ้งให้คอมไพเลอร์ Compose ทราบว่าฟังก์ชันนี้มีไว้เพื่อแปลงข้อมูลเป็น UIฟังก์ชันรับข้อมูล ฟังก์ชัน Composable ยอมรับพารามิเตอร์ได้ ซึ่งช่วยให้ตรรกะของแอปอธิบาย UI ได้ ในกรณีนี้ วิดเจ็ตของเรายอมรับ
String
เพื่อให้ทักทายผู้ใช้ด้วยชื่อได้ฟังก์ชันจะแสดงข้อความใน UI โดยเรียกใช้ฟังก์ชัน
Text()
composable ซึ่งสร้างองค์ประกอบ UI ข้อความ ฟังก์ชันที่ประกอบกันได้จะแสดงลําดับชั้น UI โดยการเรียกใช้ฟังก์ชันอื่นๆ ที่ประกอบกันได้ฟังก์ชันดังกล่าวจะไม่แสดงผลใดๆ ฟังก์ชันคอมโพสิชันที่แสดง UI ไม่จำเป็นต้องแสดงผลใดๆ เนื่องจากจะอธิบายสถานะหน้าจอที่ต้องการแทนการสร้างวิดเจ็ต UI
ฟังก์ชันนี้ทำงานเร็ว เป็นการระบุตัวตน และไม่มีผลข้างเคียง
- ฟังก์ชันจะทํางานในลักษณะเดียวกันเมื่อเรียกใช้หลายครั้งด้วยอาร์กิวเมนต์เดียวกัน และไม่ใช้ค่าอื่นๆ เช่น ตัวแปรส่วนกลางหรือการเรียกใช้
random()
- ฟังก์ชันนี้จะอธิบาย UI โดยไม่มีผลกระทบข้างเคียง เช่น การแก้ไขพร็อพเพอร์ตี้หรือตัวแปรร่วม
โดยทั่วไป ฟังก์ชัน Composable ทั้งหมดควรเขียนโดยใช้พร็อพเพอร์ตี้เหล่านี้ด้วยเหตุผลที่อธิบายไว้ในการจัดองค์ประกอบใหม่
- ฟังก์ชันจะทํางานในลักษณะเดียวกันเมื่อเรียกใช้หลายครั้งด้วยอาร์กิวเมนต์เดียวกัน และไม่ใช้ค่าอื่นๆ เช่น ตัวแปรส่วนกลางหรือการเรียกใช้
การเปลี่ยนกระบวนทัศน์แบบประกาศ
เมื่อใช้ชุดเครื่องมือ UI แบบโอบเจ็กต์ออเรียนเต็ดแบบบังคับหลายชุด คุณจะเริ่มต้น UI ได้โดยการสร้างอินสแตนซ์ของวิดเจ็ตเป็นลําดับชั้น ซึ่งมักทำโดยการขยายไฟล์เลย์เอาต์ XML วิดเจ็ตแต่ละรายการจะรักษาสถานะภายในของตนเองไว้ และแสดงเมธอด getter และ setter ที่ช่วยให้ตรรกะของแอปโต้ตอบกับวิดเจ็ตได้
ในแนวทางแบบประกาศของ Compose วิดเจ็ตจะเป็นแบบไม่มีสถานะและไม่แสดงฟังก์ชัน setter หรือ getter ความจริงแล้ว วิดเจ็ตไม่ได้แสดงเป็นออบเจ็กต์
คุณอัปเดต UI ด้วยการเรียกใช้ฟังก์ชัน Composable เดียวกันโดยใช้อาร์กิวเมนต์ที่ต่างกัน วิธีนี้ช่วยให้ระบุสถานะให้กับรูปแบบสถาปัตยกรรมต่างๆ เช่น ViewModel
ได้ง่าย ตามที่อธิบายไว้ในคู่มือสถาปัตยกรรมแอป จากนั้นคอมโพสิเบิลจะมีหน้าที่เปลี่ยนสถานะปัจจุบันของแอปพลิเคชันเป็น UI ทุกครั้งที่ข้อมูลสังเกตได้อัปเดต
รูปที่ 2 ตรรกะแอปจะส่งข้อมูลไปยังฟังก์ชันคอมโพสิเบิลระดับบนสุด ฟังก์ชันดังกล่าวใช้ข้อมูลเพื่ออธิบาย UI โดยการเรียกใช้คอมโพสิเบิลอื่นๆ และส่งต่อข้อมูลที่เหมาะสมไปยังคอมโพสิเบิลเหล่านั้น และส่งต่อตามลําดับชั้น
เมื่อผู้ใช้โต้ตอบกับ UI ทาง UI จะสร้างเหตุการณ์ เช่น onClick
เหตุการณ์เหล่านั้นควรแจ้งให้ตรรกะของแอปทราบ ซึ่งจะเปลี่ยนสถานะของแอปได้
เมื่อสถานะเปลี่ยนแปลง ระบบจะเรียกใช้ฟังก์ชันคอมโพสิเบิลอีกครั้งด้วยข้อมูลใหม่ ซึ่งจะทำให้องค์ประกอบ UI วาดใหม่ กระบวนการนี้เรียกว่าการจัดองค์ประกอบใหม่
รูปที่ 3 ผู้ใช้โต้ตอบกับองค์ประกอบ UI ซึ่งทริกเกอร์เหตุการณ์ ตรรกะของแอปจะตอบสนองต่อเหตุการณ์ จากนั้นระบบจะเรียกใช้ฟังก์ชันคอมโพสิเบิลอีกครั้งโดยอัตโนมัติด้วยพารามิเตอร์ใหม่ หากจําเป็น
เนื้อหาแบบไดนามิก
เนื่องจากฟังก์ชันคอมโพสิเบิลเขียนด้วย Kotlin แทน XML ฟังก์ชันเหล่านี้จึงเป็นแบบไดนามิกได้เช่นเดียวกับโค้ด Kotlin อื่นๆ ตัวอย่างเช่น สมมติว่าคุณต้องการสร้าง UI ต้อนรับรายชื่อผู้ใช้
@Composable fun Greeting(names: List<String>) { for (name in names) { Text("Hello $name") } }
ฟังก์ชันนี้จะรับรายการชื่อและสร้างคําทักทายสําหรับผู้ใช้แต่ละราย
ฟังก์ชันที่ประกอบกันได้มีความซับซ้อนพอสมควร คุณใช้คำสั่ง if
เพื่อตัดสินใจว่าต้องการแสดงองค์ประกอบ UI ที่เจาะจงได้ไหม คุณใช้ลูปได้ คุณสามารถเรียกใช้ฟังก์ชันตัวช่วย คุณมีความยืดหยุ่นอย่างเต็มที่ในภาษาพื้นฐาน
ความสามารถและความยืดหยุ่นนี้เป็นหนึ่งในข้อดีหลักๆ ของ Jetpack Compose
การจัดองค์ประกอบใหม่
ในโมเดล UI แบบบังคับ หากต้องการเปลี่ยนวิดเจ็ต คุณต้องเรียกใช้ตัวตั้งค่าในวิดเจ็ตเพื่อเปลี่ยนสถานะภายใน ใน 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 เขียนใหม่โดยอิงตามอินพุตใหม่ ระบบจะเรียกใช้เฉพาะฟังก์ชันหรือ lambda ที่อาจมีการเปลี่ยนแปลงและข้ามส่วนที่เหลือ การข้ามฟังก์ชันหรือ Lambda ทั้งหมดที่ไม่มีการเปลี่ยนแปลงพารามิเตอร์จะช่วยให้ Compose คอมไพล์ใหม่ได้อย่างมีประสิทธิภาพ
อย่าพึ่งพาผลข้างเคียงจากการดำเนินการฟังก์ชันคอมโพสิเบิล เนื่องจากระบบอาจข้ามการจัดเรียงใหม่ของฟังก์ชัน หากดำเนินการดังกล่าว ผู้ใช้อาจพบลักษณะการทำงานที่แปลกประหลาดและคาดเดาไม่ได้ในแอปของคุณ ผลข้างเคียงคือการเปลี่ยนแปลงที่ปรากฏในส่วนอื่นๆ ของแอป เช่น การดำเนินการต่อไปนี้ล้วนเป็นผลข้างเคียงที่อันตราย
- การเขียนไปยังพร็อพเพอร์ตี้ของออบเจ็กต์ที่แชร์
- กำลังอัปเดตรายการที่สังเกตได้ใน
ViewModel
- การอัปเดตค่ากำหนดที่แชร์
ฟังก์ชันคอมโพสิเบิลอาจทำงานซ้ำบ่อยครั้ง เช่น ทุกเฟรม เมื่อระบบกำลังแสดงผลภาพเคลื่อนไหว ฟังก์ชันคอมโพสิเบิลควรทำงานได้อย่างรวดเร็วเพื่อหลีกเลี่ยงการกระตุกระหว่างภาพเคลื่อนไหว หากต้องดำเนินการที่มีค่าใช้จ่ายสูง เช่น การอ่านจากค่ากำหนดที่แชร์ ให้ดำเนินการในโคโรทีนเบื้องหลังและส่งผลลัพธ์ค่าไปยังฟังก์ชันคอมโพสิเบิลเป็นพารามิเตอร์
ตัวอย่างเช่น โค้ดนี้สร้าง Composable เพื่ออัปเดตค่าใน SharedPreferences
Composable ไม่ควรอ่านหรือเขียนจากค่ากำหนดที่แชร์โดยตรง แต่โค้ดนี้จะย้ายการอ่านและเขียนไปยัง ViewModel
ในโครูทีนในเบื้องหลังแทน ตรรกะของแอปจะส่งค่าปัจจุบันด้วยการเรียกกลับเพื่อทริกเกอร์การอัปเดต
@Composable fun SharedPrefsToggle( text: String, value: Boolean, onValueChanged: (Boolean) -> Unit ) { Row { Text(text) Checkbox(checked = value, onCheckedChange = onValueChanged) } }
เอกสารนี้กล่าวถึงสิ่งที่ควรทราบเมื่อใช้เครื่องมือเขียน
- การคอมโพสิชันใหม่จะข้ามฟังก์ชันและ 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) })) }
แต่ละขอบเขตเหล่านี้อาจเป็นสิ่งเดียวที่จะดำเนินการในระหว่างการจัดเรียงใหม่
คอมโพซอาจข้ามไปยังแลมบ์ดา Column
โดยไม่เรียกใช้แลมบ์ดาหลักเลยเมื่อ header
เปลี่ยนแปลง และเมื่อเรียกใช้ Column
คอมโพซอาจเลือกที่จะข้ามรายการของ LazyColumn
หาก names
ไม่มีการเปลี่ยนแปลง
อีกครั้ง การดำเนินการฟังก์ชันหรือแลมบ์ดาแบบคอมโพสิเบิลทั้งหมดไม่ควรมีผลข้างเคียง เมื่อต้องการสร้างเอฟเฟกต์ข้างเคียง ให้ทริกเกอร์จาก Callback
การจัดองค์ประกอบใหม่เป็นแบบมองโลกในแง่ดี
การคอมโพสใหม่จะเริ่มขึ้นเมื่อใดก็ตามที่ Compose คิดว่าพารามิเตอร์ของคอมโพสิเบิลอาจเปลี่ยนแปลง การคอมโพสิชันใหม่เป็นแบบคาดการณ์ ซึ่งหมายความว่า Compose จะคาดหวังว่าจะคอมโพสิชันใหม่เสร็จก่อนที่พารามิเตอร์จะเปลี่ยนแปลงอีกครั้ง หากพารามิเตอร์มีการเปลี่ยนแปลงก่อนที่การจัดเรียงใหม่จะเสร็จสิ้น Compose อาจยกเลิกการจัดเรียงใหม่และเริ่มใหม่ด้วยพารามิเตอร์ใหม่
เมื่อยกเลิกการจัดเรียงใหม่ Compose จะทิ้งต้นไม้ UI จากการเรียงใหม่ หากคุณมีผลข้างเคียงที่ขึ้นอยู่กับการแสดง UI ระบบจะใช้ผลข้างเคียงนั้นแม้ว่าจะยกเลิกการคอมโพสิชันแล้วก็ตาม ซึ่งอาจทำให้แอปมีสถานะไม่สอดคล้องกัน
ตรวจสอบว่าฟังก์ชันและ Lambda แบบคอมโพสิเบิลทั้งหมดเป็นแบบ idempotent และไม่มีผลข้างเคียงเพื่อจัดการกับการจัดเรียงใหม่แบบมองโลกในแง่ดี
ฟังก์ชันที่ประกอบกันได้อาจทำงานค่อนข้างบ่อย
ในบางกรณี ฟังก์ชันคอมโพสิเบิลอาจทํางานกับเฟรม UI เคลื่อนไหวทุกเฟรม หากฟังก์ชันดำเนินการที่มีค่าใช้จ่ายสูง เช่น การอ่านจากพื้นที่เก็บข้อมูลของอุปกรณ์ ฟังก์ชันนี้อาจทำให้เกิดการกระตุกของ UI ได้
เช่น หากวิดเจ็ตพยายามอ่านการตั้งค่าอุปกรณ์ ก็อาจอ่านการตั้งค่าเหล่านั้นหลายร้อยครั้งต่อวินาที ซึ่งส่งผลเสียต่อประสิทธิภาพของแอป
หากฟังก์ชันคอมโพสิเบิลต้องใช้ข้อมูล ฟังก์ชันดังกล่าวควรกําหนดพารามิเตอร์สําหรับข้อมูล จากนั้นคุณสามารถย้ายงานที่ต้องใช้ทรัพยากรมากไปยังอีกชุดข้อความหนึ่งนอกการคอมโพสิชัน และส่งข้อมูลไปยังการคอมโพสิชันได้โดยใช้ mutableStateOf
หรือ LiveData
ฟังก์ชันที่ประกอบกันได้จะเรียกใช้พร้อมกันได้
Compose สามารถเพิ่มประสิทธิภาพการจัดองค์ประกอบใหม่โดยเรียกใช้ฟังก์ชัน Composable พร้อมกัน ซึ่งจะช่วยให้ Compose ใช้ประโยชน์จากหลายแกนได้ และเรียกใช้ฟังก์ชันคอมโพสิเบิลที่ไม่ได้อยู่บนหน้าจอในลำดับความสำคัญต่ำกว่า
การเพิ่มประสิทธิภาพนี้หมายความว่าฟังก์ชันคอมโพสิเบิลอาจทำงานภายในพูลของเทรดในเบื้องหลัง
หากฟังก์ชันที่ประกอบกันได้เรียกใช้ฟังก์ชันใน ViewModel
คอมโพสิชันอาจเรียกใช้ฟังก์ชันนั้นจากหลายเธรดพร้อมกัน
เพื่อให้แอปพลิเคชันทำงานได้อย่างถูกต้อง ฟังก์ชัน Composable ทั้งหมดไม่ควรส่งผลข้างเคียง แต่ให้ทริกเกอร์ผลข้างเคียงจากคอลแบ็ก เช่น onClick
ที่ทำงานในเธรด UI เสมอ
เมื่อเรียกใช้ฟังก์ชันคอมโพสิเบิล การเรียกใช้อาจเกิดขึ้นในเธรดอื่นจากของผู้เรียก ซึ่งหมายความว่าคุณควรหลีกเลี่ยงโค้ดที่แก้ไขตัวแปรในคอมโพสิเบิลแลมดา เนื่องจากโค้ดดังกล่าวไม่ปลอดภัยสำหรับเธรด และเป็นผลข้างเคียงที่ไม่อนุญาตของคอมโพสิเบิลแลมดา
ต่อไปนี้คือตัวอย่างการแสดงคอมโพสิเบิลที่แสดงรายการและจำนวนรายการ
@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 แบบคอมโพสิเบิลได้
ฟังก์ชันที่ประกอบกันได้จะทํางานในลําดับใดก็ได้
เมื่อดูโค้ดของฟังก์ชันคอมโพสิเบิล คุณอาจคิดว่าโค้ดจะทํางานตามลําดับที่ปรากฏ แต่เราไม่รับประกันว่าข้อมูลนี้จะเป็นความจริง หากฟังก์ชันคอมโพสิเบิลมีการเรียกใช้ฟังก์ชันคอมโพสิเบิลอื่นๆ ฟังก์ชันเหล่านั้นอาจทำงานตามลำดับใดก็ได้ คอมโพซมีตัวเลือกในการระบุว่าองค์ประกอบ UI บางรายการมีลำดับความสำคัญสูงกว่ารายการอื่นๆ และวาดรายการเหล่านั้นก่อน
ตัวอย่างเช่น สมมติว่าคุณมีโค้ดเพื่อวาด 3 หน้าจอในเลย์เอาต์แท็บ
@Composable fun ButtonRow() { MyFancyNavigation { StartScreen() MiddleScreen() EndScreen() } }
การโทรหา StartScreen
, MiddleScreen
และ EndScreen
อาจเกิดขึ้นในลำดับใดก็ได้ ซึ่งหมายความว่าคุณจะไม่สามารถกำหนดตัวแปรส่วนกลางบางอย่าง (ผลข้างเคียง) ใน StartScreen()
และทำให้ MiddleScreen()
ใช้ประโยชน์จากการเปลี่ยนแปลงนั้นได้ โดยแต่ละฟังก์ชันเหล่านั้นจะต้องมีทุกอย่างในตัว
ดูข้อมูลเพิ่มเติม
ดูข้อมูลเพิ่มเติมเกี่ยวกับวิธีคิดใน Compose และฟังก์ชันคอมโพสิเบิลได้ที่แหล่งข้อมูลเพิ่มเติมต่อไปนี้
วิดีโอ
แนะนำสำหรับคุณ
- หมายเหตุ: ข้อความลิงก์จะแสดงเมื่อ JavaScript ปิดอยู่
- Kotlin สำหรับ Jetpack Compose
- State และ Jetpack Compose
- เลเยอร์สถาปัตยกรรมของ Jetpack Compose