การเขียน

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 ที่แสดงข้อความทักทาย

ภาพหน้าจอโทรศัพท์ที่แสดงข้อความ " Hello World" และโค้ดสำหรับฟังก์ชัน Composable แบบง่ายที่สร้าง UI ดังกล่าว

รูปที่ 1 ฟังก์ชันคอมโพสิเบิลง่ายๆ ที่ส่งผ่านข้อมูลและใช้ข้อมูลดังกล่าวเพื่อแสดงผลวิดเจ็ตข้อความบนหน้าจอ

สิ่งที่ควรทราบเกี่ยวกับฟังก์ชันนี้มีดังนี้

  • ฟังก์ชันมีคำอธิบายประกอบ @Composable ฟังก์ชัน Composable ทั้งหมดต้องมีคำอธิบายประกอบนี้ คำอธิบายประกอบนี้จะแจ้งให้คอมไพเลอร์ Compose ทราบว่าฟังก์ชันนี้มีไว้เพื่อแปลงข้อมูลเป็น UI

  • ฟังก์ชันรับข้อมูล ฟังก์ชัน Composable ยอมรับพารามิเตอร์ได้ ซึ่งช่วยให้ตรรกะของแอปอธิบาย UI ได้ ในกรณีนี้ วิดเจ็ตของเรารับ String เพื่อให้ทักทายผู้ใช้ด้วยชื่อได้

  • ฟังก์ชันจะแสดงข้อความใน UI โดยเรียกใช้ฟังก์ชัน Text() composable ซึ่งสร้างองค์ประกอบ UI ข้อความ ฟังก์ชัน Composable จะแสดงลำดับชั้น UI โดยการเรียกใช้ฟังก์ชัน Composable อื่นๆ

  • ฟังก์ชันจะไม่แสดงผลใดๆ ฟังก์ชันการเขียนที่แสดง UI ไม่จำเป็นต้องแสดงผลใดๆ เนื่องจากจะอธิบายสถานะหน้าจอที่ต้องการแทนการสร้างวิดเจ็ต UI

  • ฟังก์ชันนี้ทำงานเร็ว เป็นการระบุตัวตน และไม่มีผลข้างเคียง

    • ฟังก์ชันจะทํางานในลักษณะเดียวกันเมื่อเรียกใช้หลายครั้งด้วยอาร์กิวเมนต์เดียวกัน และไม่ใช้ค่าอื่นๆ เช่น ตัวแปรส่วนกลางหรือการเรียกใช้ random()
    • ฟังก์ชันจะอธิบาย UI โดยไม่มีผลข้างเคียง เช่น การแก้ไขพร็อพเพอร์ตี้หรือตัวแปรส่วนกลาง

    โดยทั่วไปแล้ว ฟังก์ชันแบบคอมโพสิเบิลทั้งหมดควรเขียนด้วยพร็อพเพอร์ตี้เหล่านี้ เนื่องด้วยเหตุผลที่อธิบายไว้ในการจัดเรียงใหม่

การเปลี่ยนกระบวนทัศน์แบบประกาศ

เมื่อใช้ชุดเครื่องมือ UI แบบโอบเจ็กต์ออเรียนเต็ดแบบบังคับหลายชุด คุณจะเริ่มต้น UI ได้โดยการสร้างอินสแตนซ์ของวิดเจ็ตเป็นลําดับชั้น คุณทำแบบนี้ได้โดยการขยายไฟล์เค้าโครง XML วิดเจ็ตแต่ละรายการจะรักษาสถานะภายในของตนเองไว้ และแสดงเมธอด getter และ setter ที่ช่วยให้ตรรกะของแอปโต้ตอบกับวิดเจ็ตได้

ในแนวทางการประกาศของ Compose วิดเจ็ตจะค่อนข้างไม่เก็บสถานะและไม่แสดงฟังก์ชัน Setter หรือ Getter ที่จริงแล้ว วิดเจ็ตไม่ได้แสดงในรูปแบบของวัตถุ คุณอัปเดต UI ได้โดยเรียกใช้ฟังก์ชันคอมโพสิเบิลเดียวกันที่มีอาร์กิวเมนต์ต่างกัน วิธีนี้ช่วยให้ระบุสถานะให้กับรูปแบบสถาปัตยกรรมต่างๆ เช่น ViewModel ได้ง่าย ตามที่อธิบายไว้ในคู่มือสถาปัตยกรรมแอป จากนั้น Composable จะมีหน้าที่เปลี่ยนรูปแบบสถานะของแอปพลิเคชันปัจจุบันเป็น UI ทุกครั้งที่อัปเดตข้อมูลที่สังเกตได้

ภาพโฟลว์ข้อมูลใน UI ของการเขียน จากออบเจ็กต์ระดับสูงไปจนถึงรายการย่อย

รูปที่ 2 ตรรกะแอปจะส่งข้อมูลไปยังฟังก์ชันคอมโพสิเบิลระดับบนสุด ฟังก์ชันดังกล่าวใช้ข้อมูลเพื่ออธิบาย UI โดยการเรียกใช้คอมโพสิเบิลอื่นๆ และส่งต่อข้อมูลที่เหมาะสมไปยังคอมโพสิเบิลเหล่านั้น และส่งต่อตามลําดับชั้น

เมื่อผู้ใช้โต้ตอบกับ UI ทาง UI จะสร้างเหตุการณ์ เช่น onClick เหตุการณ์เหล่านั้นควรแจ้งตรรกะแอป ซึ่งจะเปลี่ยนสถานะของแอปได้ เมื่อสถานะเปลี่ยนแปลง ระบบจะเรียกใช้ฟังก์ชัน Composable อีกครั้งพร้อมข้อมูลใหม่ ซึ่งจะทำให้องค์ประกอบ UI วาดใหม่ กระบวนการนี้เรียกว่าการจัดองค์ประกอบใหม่

ภาพวิธีที่องค์ประกอบ UI ตอบสนองต่อการโต้ตอบ โดยทริกเกอร์เหตุการณ์ที่ดำเนินการโดย App Logic

รูปที่ 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 ไม่มีการเปลี่ยนแปลง

อีกครั้ง การดำเนินการฟังก์ชันหรือแลมบ์ดาแบบคอมโพสิเบิลทั้งหมดไม่ควรมีผลข้างเคียง เมื่อต้องการดำเนินการผลข้างเคียง ให้ทริกเกอร์จากคอลแบ็ก

การจัดองค์ประกอบใหม่เป็นแบบมองโลกในแง่ดี

การคอมโพสใหม่จะเริ่มขึ้นเมื่อใดก็ตามที่ Compose คิดว่าพารามิเตอร์ของคอมโพสิเบิลอาจเปลี่ยนแปลง การคอมโพสิชันใหม่เป็นแบบคาดการณ์ ซึ่งหมายความว่า Compose จะคาดหวังว่าจะคอมโพสิชันใหม่เสร็จก่อนที่พารามิเตอร์จะเปลี่ยนแปลงอีกครั้ง หากพารามิเตอร์มีการเปลี่ยนแปลงก่อนที่การจัดเรียงใหม่จะเสร็จสิ้น Compose อาจยกเลิกการจัดเรียงใหม่และเริ่มใหม่ด้วยพารามิเตอร์ใหม่

เมื่อยกเลิกการจัดเรียงใหม่ Compose จะทิ้งต้นไม้ UI จากการเรียงใหม่ หากคุณมีผลข้างเคียงที่ขึ้นอยู่กับการแสดง UI ระบบจะใช้ผลข้างเคียงนั้นแม้ว่าจะยกเลิกการคอมโพสิชันแล้วก็ตาม ซึ่งอาจทําให้สถานะแอปไม่สอดคล้องกัน

ตรวจสอบว่าฟังก์ชันและ Lambda แบบคอมโพสิเบิลทั้งหมดเป็นแบบ idempotent และไม่มีผลข้างเคียงเพื่อจัดการกับการจัดเรียงใหม่แบบมองโลกในแง่ดี

ฟังก์ชันที่ประกอบกันได้อาจทำงานบ่อยครั้ง

ในบางกรณี ฟังก์ชันคอมโพสิเบิลอาจทํางานกับเฟรม UI เคลื่อนไหวทุกเฟรม หากฟังก์ชันดำเนินการที่มีค่าใช้จ่ายสูง เช่น การอ่านจากพื้นที่เก็บข้อมูลของอุปกรณ์ ฟังก์ชันดังกล่าวอาจทําให้ UI กระตุก

เช่น หากวิดเจ็ตพยายามอ่านการตั้งค่าอุปกรณ์ ก็อาจอ่านการตั้งค่าเหล่านั้นหลายร้อยครั้งต่อวินาที ซึ่งส่งผลเสียต่อประสิทธิภาพของแอป

หากฟังก์ชันคอมโพสิเบิลต้องใช้ข้อมูล ฟังก์ชันดังกล่าวควรกําหนดพารามิเตอร์สําหรับข้อมูล จากนั้นคุณจะย้ายงานที่มีราคาสูงไปยังชุดข้อความอื่นที่อยู่นอกองค์ประกอบ และส่งผ่านข้อมูลไปยัง Compose โดยใช้ mutableStateOf หรือ LiveData ได้

ฟังก์ชันที่ประกอบกันได้สามารถทํางานพร้อมกันได้

คอมโพซอาจเพิ่มประสิทธิภาพการจัดเรียงใหม่ด้วยการทำงานฟังก์ชันคอมโพสิเบิลพร้อมกัน วิธีนี้จะช่วยให้ Compose ใช้ประโยชน์จากหลายแกน และเรียกใช้ฟังก์ชันที่ประกอบกันได้ซึ่งไม่ได้อยู่ในหน้าจอที่มีลำดับความสำคัญต่ำกว่า

การเพิ่มประสิทธิภาพนี้หมายความว่าฟังก์ชันคอมโพสิเบิลอาจทำงานภายในพูลของเทรดในเบื้องหลัง หากฟังก์ชันที่ประกอบกันได้เรียกใช้ฟังก์ชันใน ViewModel คอมโพสิชันอาจเรียกใช้ฟังก์ชันนั้นจากหลายเธรดพร้อมกัน

ฟังก์ชันคอมโพสิเบิลทั้งหมดไม่ควรมีผลข้างเคียงเพื่อให้แอปพลิเคชันทำงานได้อย่างถูกต้อง แต่ให้ทริกเกอร์ผลข้างเคียงจากคอลแบ็ก เช่น 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 และฟังก์ชันคอมโพสิเบิลได้ที่แหล่งข้อมูลเพิ่มเติมต่อไปนี้

วิดีโอ

ไม่มีคำแนะนำในขณะนี้

ลองบัญชี Google