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ฟังก์ชันจะรับข้อมูล ฟังก์ชันที่ประกอบกันได้จะยอมรับพารามิเตอร์ ซึ่งช่วยให้ตรรกะของแอปอธิบาย UI ได้ ในกรณีนี้ วิดเจ็ตของเรา ยอมรับ
String
เพื่อให้ทักทายผู้ใช้ตามชื่อได้ฟังก์ชันจะแสดงข้อความใน UI โดยจะเรียกใช้ฟังก์ชันที่ประกอบกันได้
Text()
ซึ่งสร้างองค์ประกอบ UI ของข้อความจริงๆ ฟังก์ชันที่ประกอบกันได้ จะส่งลําดับชั้น UI โดยการเรียกฟังก์ชันที่ประกอบกันได้อื่นๆฟังก์ชันจะไม่แสดงผลสิ่งใด ฟังก์ชัน Compose ที่ปล่อย UI ไม่จำเป็นต้องแสดงผลอะไร เนื่องจากฟังก์ชันจะอธิบายสถานะหน้าจอที่ต้องการแทนที่จะสร้างวิดเจ็ต UI
ฟังก์ชันนี้รวดเร็ว ทำซ้ำได้ และไม่มีผลข้างเคียง
- ฟังก์ชันจะทํางานในลักษณะเดียวกันเมื่อเรียกใช้หลายครั้งด้วยอาร์กิวเมนต์เดียวกัน และจะไม่ใช้ค่าอื่นๆ เช่น ตัวแปรส่วนกลางหรือการเรียกใช้
random()
- ฟังก์ชันจะอธิบาย UI โดยไม่มีผลข้างเคียง เช่น การแก้ไขพร็อพเพอร์ตี้หรือตัวแปรส่วนกลาง
โดยทั่วไป ฟังก์ชันที่สามารถคอมโพสได้ทั้งหมดควรเขียนด้วยพร็อพเพอร์ตี้เหล่านี้ด้วยเหตุผลที่กล่าวถึงในการคอมโพสใหม่
- ฟังก์ชันจะทํางานในลักษณะเดียวกันเมื่อเรียกใช้หลายครั้งด้วยอาร์กิวเมนต์เดียวกัน และจะไม่ใช้ค่าอื่นๆ เช่น ตัวแปรส่วนกลางหรือการเรียกใช้
การเปลี่ยนกระบวนทัศน์แบบประกาศ
เมื่อใช้ชุดเครื่องมือ UI แบบออบเจ็กต์เชิงคำสั่งหลายชุด คุณจะเริ่มต้น UI โดย สร้างอินสแตนซ์ของแผนผังวิดเจ็ต โดยมักจะทำได้ด้วยการขยายไฟล์เลย์เอาต์ XML วิดเจ็ตแต่ละรายการจะรักษาสถานะภายในของตัวเอง และแสดงเมธอด Getter และ Setter ที่ช่วยให้ตรรกะของแอปโต้ตอบกับวิดเจ็ตได้
ในแนวทางแบบประกาศของ Compose วิดเจ็ตจะไม่มีสถานะโดยเปรียบเทียบและไม่แสดงฟังก์ชัน Setter หรือ Getter
ในความเป็นจริงแล้ว ระบบไม่ได้แสดงวิดเจ็ตเป็นออบเจ็กต์
คุณอัปเดต UI ได้โดยการเรียกใช้ฟังก์ชันที่ประกอบกันได้เดียวกันด้วยอาร์กิวเมนต์ที่แตกต่างกัน
ซึ่งช่วยให้ระบุสถานะในรูปแบบสถาปัตยกรรม เช่น ViewModel
ได้ง่ายตามที่อธิบายไว้ในคู่มือสถาปัตยกรรมแอป จากนั้น Composable จะ
มีหน้าที่แปลงสถานะแอปพลิเคชันปัจจุบันเป็น UI ทุกครั้งที่
ข้อมูลที่สังเกตได้มีการอัปเดต
รูปที่ 2 ตรรกะของแอปจะให้ข้อมูลแก่ฟังก์ชันที่ใช้ร่วมกันได้ระดับบนสุด ฟังก์ชันดังกล่าวใช้ข้อมูลเพื่ออธิบาย UI โดยการเรียก Composable อื่นๆ และ ส่งข้อมูลที่เหมาะสมไปยัง Composable เหล่านั้นและลงไปตามลำดับชั้น
เมื่อผู้ใช้โต้ตอบกับ 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 แบบคำสั่ง หากต้องการเปลี่ยนวิดเจ็ต คุณจะต้องเรียกใช้ 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 สามารถทำการ Recompose ได้อย่างมีประสิทธิภาพ
อย่าพึ่งพาผลข้างเคียงจากการเรียกใช้ฟังก์ชันที่ประกอบกันได้ เนื่องจากอาจมีการข้ามการจัดองค์ประกอบใหม่ของฟังก์ชัน หากทำเช่นนั้น ผู้ใช้อาจพบพฤติกรรมที่แปลกประหลาด และคาดเดาไม่ได้ในแอปของคุณ ผลข้างเคียงคือการเปลี่ยนแปลงใดๆ ที่ มองเห็นได้ในส่วนอื่นๆ ของแอป ตัวอย่างเช่น การดำเนินการต่อไปนี้เป็นผลข้างเคียงที่อันตราย ทั้งหมด
- การเขียนไปยังพร็อพเพอร์ตี้ของออบเจ็กต์ที่แชร์
- การอัปเดตข้อมูลที่สังเกตได้ใน
ViewModel
- การอัปเดตค่ากำหนดที่แชร์
ระบบอาจเรียกใช้ฟังก์ชันที่ประกอบกันได้อีกครั้งบ่อยเท่าทุกเฟรม เช่น เมื่อ มีการแสดงภาพเคลื่อนไหว ฟังก์ชันที่ประกอบกันได้ควรทำงานอย่างรวดเร็วเพื่อหลีกเลี่ยง การกระตุกระหว่างภาพเคลื่อนไหว หากคุณต้องการดำเนินการที่มีค่าใช้จ่ายสูง เช่น การอ่านจากค่ากำหนดที่ใช้ร่วมกัน ให้ดำเนินการในโครูทีนเบื้องหลังและส่งผลลัพธ์ค่าไปยังฟังก์ชันที่ใช้ร่วมกันเป็นพารามิเตอร์
ตัวอย่างเช่น โค้ดนี้จะสร้าง Composable เพื่ออัปเดตค่าใน SharedPreferences
Composable ไม่ควรอ่านหรือเขียนจาก Shared
Preferences เอง แต่โค้ดนี้จะย้ายการอ่านและการเขียนไปยัง ViewModel
ในโครูทีนเบื้องหลังแทน ตรรกะของแอปจะส่งค่าปัจจุบันพร้อม
การเรียกกลับเพื่อทริกเกอร์การอัปเดต
@Composable fun SharedPrefsToggle( text: String, value: Boolean, onValueChanged: (Boolean) -> Unit ) { Row { Text(text) Checkbox(checked = value, onCheckedChange = onValueChanged) } }
เอกสารนี้จะกล่าวถึงสิ่งต่างๆ ที่ควรทราบเมื่อใช้ Compose
- การประกอบใหม่จะข้ามฟังก์ชันที่ประกอบกันได้และ Lambda ให้ได้มากที่สุด
- การประกอบใหม่เป็นการดำเนินการแบบมองโลกในแง่ดีและอาจถูกยกเลิก
- ระบบอาจเรียกใช้ฟังก์ชันที่ประกอบกันได้ค่อนข้างบ่อย ซึ่งอาจเป็นทุกเฟรม ของภาพเคลื่อนไหว
- ฟังก์ชันที่ประกอบกันได้จะดำเนินการแบบขนานได้
- ฟังก์ชันที่ประกอบกันได้จะดำเนินการตามลำดับใดก็ได้
ส่วนต่อไปนี้จะครอบคลุมวิธีสร้างฟังก์ชันที่ใช้ร่วมกันได้เพื่อรองรับ การจัดองค์ประกอบใหม่ ในทุกกรณี แนวทางปฏิบัติแนะนำคือการทำให้ฟังก์ชันที่ประกอบได้ ทำงานได้อย่างรวดเร็ว มีการดำเนินการซ้ำได้ และไม่มีผลข้างเคียง
ข้ามการจัดองค์ประกอบใหม่ให้ได้มากที่สุด
เมื่อส่วนต่างๆ ของ UI ไม่ถูกต้อง Compose จะพยายามอย่างเต็มที่เพื่อทำการประกอบใหม่เฉพาะส่วนที่ต้องอัปเดตเท่านั้น ซึ่งหมายความว่าอาจข้ามไปเรียกใช้ Composable ของ Button รายการเดียวอีกครั้งโดยไม่ต้องเรียกใช้ Composable ใดๆ ที่อยู่เหนือหรือใต้ Composable นั้นในแผนผัง 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
โดยไม่เรียกใช้ Lambda ระดับบน
เมื่อ header
เปลี่ยนแปลง และเมื่อเรียกใช้ Column
, Compose อาจเลือกที่จะ
ข้ามรายการของ LazyColumn
หาก names
ไม่มีการเปลี่ยนแปลง
อีกครั้งที่การเรียกใช้ฟังก์ชันที่ประกอบได้หรือ Lambda ทั้งหมดไม่ควรมีผลข้างเคียง เมื่อต้องการดำเนินการที่มีผลข้างเคียง ให้ทริกเกอร์จากโค้ดเรียกกลับ
การจัดองค์ประกอบใหม่เป็นแบบมองในแง่ดี
การประกอบใหม่จะเริ่มเมื่อใดก็ตามที่ Compose คิดว่าพารามิเตอร์ของ Composable อาจมีการเปลี่ยนแปลง การประกอบใหม่เป็นแบบมองในแง่ดี ซึ่งหมายความว่า Compose คาดหวัง ที่จะประกอบใหม่ให้เสร็จก่อนที่พารามิเตอร์จะเปลี่ยนแปลงอีกครั้ง หากพารามิเตอร์มีการเปลี่ยนแปลงก่อนที่การจัดองค์ประกอบใหม่จะเสร็จสมบูรณ์ Compose อาจยกเลิกการจัดองค์ประกอบใหม่และรีสตาร์ทด้วยพารามิเตอร์ใหม่
เมื่อยกเลิกการจัดองค์ประกอบใหม่ Compose จะทิ้งแผนผัง UI จากการจัดองค์ประกอบใหม่ หากคุณมีผลข้างเคียงที่ขึ้นอยู่กับการแสดง UI ผลข้างเคียงจะยังคงมีผลแม้ว่าจะยกเลิกการจัดองค์ประกอบแล้วก็ตาม ซึ่งอาจส่งผลให้สถานะของแอปไม่สอดคล้องกัน
ตรวจสอบว่าฟังก์ชันที่ประกอบได้และ Lambda ทั้งหมดเป็นแบบ Idempotent และไม่มีผลข้างเคียง เพื่อจัดการการประกอบใหม่แบบมองโลกในแง่ดี
ฟังก์ชันที่ประกอบกันได้อาจทำงานบ่อยมาก
ในบางกรณี ฟังก์ชันที่ประกอบกันได้อาจทํางานสําหรับทุกเฟรมของภาพเคลื่อนไหว UI หากฟังก์ชันดำเนินการที่มีค่าใช้จ่ายสูง เช่น การอ่านจาก ที่เก็บข้อมูลของอุปกรณ์ ฟังก์ชันอาจทำให้ UI กระตุก
เช่น หากวิดเจ็ตพยายามอ่านการตั้งค่าอุปกรณ์ วิดเจ็ตอาจอ่านการตั้งค่าเหล่านั้นหลายร้อยครั้งต่อวินาที ซึ่งจะส่งผลเสียต่อประสิทธิภาพของแอป
หากฟังก์ชันที่ใช้ร่วมกันได้ต้องใช้ข้อมูล ฟังก์ชันควรระบุพารามิเตอร์สำหรับ
ข้อมูล จากนั้นคุณสามารถย้ายงานที่ใช้ทรัพยากรมากไปยังเธรดอื่นนอกmutableStateOf
Composition และส่งข้อมูลไปยัง Compose โดยใช้ mutableStateOf
หรือ LiveData
เรียกใช้ฟังก์ชันที่ประกอบกันได้แบบขนานได้
Compose สามารถเพิ่มประสิทธิภาพการจัดองค์ประกอบใหม่ได้โดยการเรียกใช้ฟังก์ชันที่ประกอบกันได้แบบ ขนาน ซึ่งจะช่วยให้ Compose ใช้ประโยชน์จากหลายแกนได้ และเรียกใช้ฟังก์ชันที่ใช้ร่วมกันได้ซึ่งไม่ได้อยู่บนหน้าจอด้วยลำดับความสำคัญที่ต่ำกว่า
การเพิ่มประสิทธิภาพนี้หมายความว่าฟังก์ชันที่ใช้ร่วมกันได้อาจทำงานภายในกลุ่มของเธรดเบื้องหลัง
หากฟังก์ชันที่ประกอบกันได้เรียกฟังก์ชันใน ViewModel
,
Compose อาจเรียกฟังก์ชันนั้นจากหลายเธรดพร้อมกัน
ฟังก์ชันที่ใช้ร่วมกันได้ทั้งหมดไม่ควรมีผลข้างเคียงเพื่อให้แอปพลิเคชันทำงานได้อย่างถูกต้อง
แต่ให้ทริกเกอร์ผลข้างเคียงจากโค้ดเรียกกลับ เช่น
onClick
ซึ่งจะทำงานใน UI เธรดเสมอ
เมื่อเรียกใช้ฟังก์ชันที่ใช้ร่วมกันได้ การเรียกใช้อาจเกิดขึ้นใน เธรดที่แตกต่างจากผู้เรียก ซึ่งหมายความว่าควรหลีกเลี่ยงโค้ดที่แก้ไขตัวแปรใน Composable Lambda ทั้งนี้เนื่องจากโค้ดดังกล่าวไม่ปลอดภัยต่อเธรด และเนื่องจาก เป็นผลข้างเคียงที่ไม่ได้รับอนุญาตของ Composable Lambda
ต่อไปนี้เป็นตัวอย่างที่แสดง 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 จึงไม่รองรับการเขียนแบบนี้ การห้ามการเขียนดังกล่าวช่วยให้เฟรมเวิร์กเปลี่ยนเธรดเพื่อเรียกใช้แลมบ์ดาที่ใช้ร่วมกันได้
ฟังก์ชันที่ประกอบกันได้จะดำเนินการตามลำดับใดก็ได้
หากดูโค้ดของฟังก์ชันที่ใช้ร่วมกันได้ คุณอาจคิดว่า โค้ดจะทำงานตามลำดับที่ปรากฏ แต่ก็ไม่รับประกันว่าจะเป็นเช่นนั้น หากฟังก์ชันที่ใช้ร่วมกันได้มีคำสั่งเรียกฟังก์ชันที่ใช้ร่วมกันได้อื่นๆ ฟังก์ชันเหล่านั้นอาจทำงานตามลำดับใดก็ได้ Compose มีตัวเลือกในการรับรู้ว่าองค์ประกอบ UI บางอย่างมีความสำคัญสูงกว่าองค์ประกอบอื่นๆ และวาดองค์ประกอบเหล่านั้นก่อน
ตัวอย่างเช่น สมมติว่าคุณมีโค้ดลักษณะนี้เพื่อวาดหน้าจอ 3 หน้าในเลย์เอาต์แท็บ
@Composable fun ButtonRow() { MyFancyNavigation { StartScreen() MiddleScreen() EndScreen() } }
การโทรหา StartScreen
, MiddleScreen
และ EndScreen
อาจเกิดขึ้นตามลำดับใดก็ได้ ซึ่งหมายความว่าคุณไม่สามารถ เช่น StartScreen()
ตั้งค่าตัวแปรส่วนกลางบางอย่าง (ผลข้างเคียง) และให้ MiddleScreen()
ใช้ประโยชน์จากการเปลี่ยนแปลงนั้นได้ แต่ฟังก์ชันแต่ละอย่างต้องมีข้อมูลที่จำเป็นทั้งหมดในตัว
ดูข้อมูลเพิ่มเติม
ดูข้อมูลเพิ่มเติมเกี่ยวกับวิธีคิดใน Compose และฟังก์ชันที่ใช้ร่วมกันได้ได้จาก แหล่งข้อมูลเพิ่มเติมต่อไปนี้
วิดีโอ
แนะนำสำหรับคุณ
- หมายเหตุ: ข้อความลิงก์จะแสดงเมื่อ JavaScript ปิดอยู่
- Kotlin สำหรับ Jetpack Compose
- สถานะและ Jetpack Compose
- การแบ่งเลเยอร์สถาปัตยกรรมของ Jetpack Compose