ในหน้านี้ คุณจะได้เรียนรู้เกี่ยวกับวงจรของ Composable และ วิธีที่ Compose ใช้ในการตัดสินว่าจะต้องจัดองค์ประกอบใหม่สำหรับ Composable หรือไม่
ภาพรวมของวงจร
ตามที่ระบุไว้ในเอกสารประกอบของการจัดการสถานะ การเรียบเรียงอธิบาย UI ของแอปและสร้างขึ้นโดยการเรียกใช้ Composable การเรียบเรียงเป็นโครงสร้างแบบต้นไม้ของ Composable ที่อธิบาย UI ของคุณ
เมื่อ Jetpack Compose เรียกใช้ Composable เป็นครั้งแรกระหว่างครั้งแรก ของคอมโพเนนต์ ระบบจะติดตาม Composable ที่คุณเรียกใช้เพื่ออธิบาย UI ในการเรียบเรียง จากนั้นเมื่อสถานะของแอปเปลี่ยนไป Jetpack การเขียนจะกำหนดเวลาการจัดองค์ประกอบใหม่ การจัดองค์ประกอบใหม่คือการใช้ Jetpack Compose เรียกใช้ Composable อีกครั้งอาจมีการเปลี่ยนแปลงเพื่อตอบสนองต่อการเปลี่ยนแปลงสถานะ จากนั้นจึงอัปเดตการเรียบเรียงเพื่อแสดงการเปลี่ยนแปลง
การเรียบเรียงเพลงจะสร้างโดยการเรียบเรียงเพลงเริ่มต้นและอัปเดตโดย การจัดองค์ประกอบใหม่ วิธีเดียวในการแก้ไขการเรียบเรียงคือผ่านการจัดองค์ประกอบใหม่
รูปที่ 1 วงจรของ Composable ในการเรียบเรียง จะเข้าสู่ การเรียบเรียง ได้รับการจัดองค์ประกอบใหม่ตั้งแต่ 0 ครั้งขึ้นไป แล้วออกจากการเรียบเรียง
โดยทั่วไปการจัดองค์ประกอบใหม่จะทริกเกอร์โดยการเปลี่ยนแปลง
State<T>
เขียน
ติดตามสิ่งเหล่านี้และเรียกใช้ Composable ทั้งหมดในการเรียบเรียงที่อ่านค่า
State<T>
โดยเฉพาะ และ Composable ที่เรียกใช้ซึ่งไม่สามารถ
ข้าม
หากมีการเรียกใช้ Composable หลายครั้ง จะมีหลายอินสแตนซ์อยู่ในพารามิเตอร์ การเรียบเรียง การเรียกแต่ละรายการมีวงจรชีวิตในการเรียบเรียงของตัวเอง
@Composable fun MyComposable() { Column { Text("Hello") Text("World") } }
รูปที่ 2 การแทนค่า MyComposable
ในการเรียบเรียง หากมี
Composable มีการเรียกใช้หลายครั้ง โดยจะมีอินสแตนซ์หลายรายการวางอยู่ใน
การเรียบเรียง องค์ประกอบที่มีสีต่างกันจะบ่งชี้ว่าเป็น
แยกอินสแตนซ์
กายวิภาคของ Composable ในการเรียบเรียง
อินสแตนซ์ของ Composable ในการเรียบเรียงจะระบุโดยไซต์การเรียกใช้ คอมไพเลอร์ Compose จะถือว่าเว็บไซต์การเรียกแต่ละแห่งแตกต่างกัน กำลังเรียก Composable จากเว็บไซต์การเรียกใช้หลายแห่งจะสร้างอินสแตนซ์ Composable หลายอินสแตนซ์ใน การเรียบเรียง
หาก Composable เรียก Composable ระหว่างการจัดองค์ประกอบใหม่แตกต่างจากที่เรียก Composable ในระหว่างการเขียนก่อนหน้านี้ Compose จะ ระบุว่า Composable ใดได้รับการระบุ เรียกใช้หรือไม่เรียกใช้ และสำหรับ Composable ที่มีการเรียกใช้ทั้งใน การแต่งเพลง Compose จะหลีกเลี่ยงการจัดองค์ประกอบใหม่หากอินพุตไม่ มีการเปลี่ยนแปลง
การรักษาข้อมูลประจำตัวเป็นสิ่งสำคัญในการเชื่อมโยงผลข้างเคียงกับ Composable เพื่อให้ดำเนินการได้เสร็จสมบูรณ์ แทนที่จะต้องเริ่มใหม่ทุก การจัดองค์ประกอบใหม่
ลองดูตัวอย่างต่อไปนี้
@Composable fun LoginScreen(showError: Boolean) { if (showError) { LoginError() } LoginInput() // This call site affects where LoginInput is placed in Composition } @Composable fun LoginInput() { /* ... */ } @Composable fun LoginError() { /* ... */ }
ในข้อมูลโค้ดด้านบน LoginScreen
จะเรียกฟังก์ชัน
LoginError
Composable และเรียก LoginInput
Composable เสมอ ชิ้น
มีไซต์การเรียกใช้และตำแหน่งแหล่งที่มาที่ไม่ซ้ำกัน ซึ่งคอมไพเลอร์จะใช้เพื่อ
เป็นเอกลักษณ์ของตัวเองได้
รูปที่ 3 การแสดง LoginScreen
ในการเรียบเรียงเมื่อสถานะ
และการจัดองค์ประกอบใหม่จะเกิดขึ้น สีเดียวกันหมายความว่ายังไม่ได้ปรับองค์ประกอบใหม่
แม้ว่า LoginInput
จากชื่อที่ 1 เป็นชื่อที่ 2 แล้วก็ตาม
ระบบจะเก็บรักษาอินสแตนซ์ LoginInput
ในการจัดองค์ประกอบใหม่ นอกจากนี้
เนื่องจาก LoginInput
ไม่มีพารามิเตอร์ที่มีการเปลี่ยนแปลงใน
การจัดองค์ประกอบใหม่ การเขียนจะข้ามการเรียกไปยัง LoginInput
ใส่ข้อมูลเพิ่มเติมเพื่อช่วยจัดองค์ประกอบใหม่อย่างชาญฉลาด
การเรียก Composable หลายครั้งจะเพิ่มไปยังการเรียบเรียงหลายครั้งเป็น เมื่อเรียก Composable หลายครั้งจากเว็บไซต์การโทรเดียวกัน Compose ไม่มีข้อมูลที่จะระบุการเรียกแต่ละรายการไปยัง Composable เพื่อให้มีการใช้ลำดับการดำเนินการนอกเหนือจากไซต์การเรียกใช้เพื่อให้ อินสแตนซ์ที่แตกต่างกัน ในบางครั้ง คุณจำเป็นต้องใช้ลักษณะการทำงานนี้ แต่ในบางกรณี อาจส่งผลให้เกิดพฤติกรรมที่ไม่พึงประสงค์
@Composable fun MoviesScreen(movies: List<Movie>) { Column { for (movie in movies) { // MovieOverview composables are placed in Composition given its // index position in the for loop MovieOverview(movie) } } }
ในตัวอย่างข้างต้น Compose จะใช้ลำดับการดำเนินการเพิ่มเติมจากการเรียกใช้
เพื่อให้อินสแตนซ์
มีความแตกต่างในการเรียบเรียง หากเพิ่ม movie
ใหม่
ที่ด้านล่างของรายการ Compose สามารถใช้อินสแตนซ์ที่มีอยู่แล้วใน
องค์ประกอบตั้งแต่ตำแหน่งในรายการไม่มีการเปลี่ยนแปลง ด้วยเหตุนี้
อินพุต movie
สำหรับอินสแตนซ์เหล่านั้นจะเหมือนกัน
รูปที่ 4 การแสดง MoviesScreen
ในการเรียบเรียงเมื่อ
ไว้ที่ด้านล่างของรายการ Composable MovieOverview
รายการใน
นำการเรียบเรียงมาใช้ซ้ำได้ สีเดียวกันใน MovieOverview
หมายถึง Composable
ยังไม่ได้เขียนใหม่
แต่ถ้ารายการ movies
เปลี่ยนแปลงโดยการเพิ่มที่ ด้านบน หรือ
ตรงกลางของรายการ การนำรายการออกหรือเรียงลำดับใหม่ จะทำให้เกิดการจัดเรียงใหม่
ในการเรียก MovieOverview
ทั้งหมดซึ่งพารามิเตอร์อินพุตเปลี่ยนตำแหน่งใน
รายการ ซึ่งมีความสำคัญมาก ตัวอย่างเช่น หาก MovieOverview
ดึงข้อมูล
รูปภาพภาพยนตร์ที่ใช้เอฟเฟกต์ข้าง หากการจัดองค์ประกอบใหม่เกิดขึ้นขณะที่เอฟเฟกต์อยู่ใน
ความคืบหน้าจะถูกยกเลิกและจะเริ่มใหม่อีกครั้ง
@Composable fun MovieOverview(movie: Movie) { Column { // Side effect explained later in the docs. If MovieOverview // recomposes, while fetching the image is in progress, // it is cancelled and restarted. val image = loadNetworkImage(movie.url) MovieHeader(image) /* ... */ } }
รูปที่ 5 การแสดง MoviesScreen
ในการเรียบเรียงเมื่อ
ลงในรายการ Composable MovieOverview
รายการไม่สามารถนำมาใช้ซ้ำและ
ผลข้างเคียงทั้งหมดจะเริ่มต้นใหม่ สีอื่นใน MovieOverview
หมายถึง
มีการคอมไพล์ Composable ใหม่แล้ว
ตามหลักการ เราต้องการให้คิดว่าเอกลักษณ์ของอินสแตนซ์ MovieOverview
คือ
ลิงก์กับข้อมูลประจำตัวของ movie
ที่ส่งไปยัง หากเราเรียงลำดับ
ของภาพยนตร์ หากเป็นไปได้ เราควรจัดเรียงอินสแตนซ์ใน
แผนผังการเรียบเรียงแทนที่จะเขียน MovieOverview
แต่ละรายการที่เขียนได้ด้วย
ภาพยนตร์ตัวอย่างอื่นๆ การเขียนช่วยให้คุณบอกรันไทม์ได้
ค่าที่คุณต้องการใช้เพื่อระบุส่วนที่กำหนดของต้นไม้ ซึ่งได้แก่
key
Composable
รวมกลุ่มโค้ดด้วยการเรียกไปยังคีย์ที่ประกอบได้ด้วย 1 หรือหลายรายการ
ค่าที่ส่งไปแล้ว ระบบจะรวมค่าเหล่านั้นเข้าด้วยกันเพื่อใช้ระบุ
ในการเขียน ค่าของ key
ไม่จำเป็นต้องเป็น
ทั่วโลก ต้องไม่ซ้ำกัน เฉพาะในระหว่างการเรียกใช้
Composable ที่ไซต์การโทร ดังนั้นในตัวอย่างนี้ movie
แต่ละรายการต้องมีแอตทริบิวต์
key
ที่ไม่ซ้ำกันระหว่าง movies
ก็ไม่เป็นไรหากแชร์ key
นั้นกับ
อื่นๆ ที่เขียนได้ด้วย Compose ในที่อื่นๆ ในแอป
@Composable fun MoviesScreenWithKey(movies: List<Movie>) { Column { for (movie in movies) { key(movie.id) { // Unique ID for this movie MovieOverview(movie) } } } }
ด้วยเงื่อนไขข้างต้น แม้ว่าองค์ประกอบในรายการจะมีการเปลี่ยนแปลง แต่ Compose จะจดจำได้
การโทรแต่ละครั้งไปยัง MovieOverview
และสามารถใช้ซ้ำได้
รูปที่ 6 การแสดง MoviesScreen
ในการเรียบเรียงเมื่อ
ลงในรายการ เนื่องจาก Composable MovieOverview
มีรายการที่ไม่ซ้ำกัน
โดย Compose จะจดจำอินสแตนซ์ MovieOverview
รายการที่ไม่มีการเปลี่ยนแปลง และ
สามารถใช้ซ้ำได้ ผลข้างเคียงจะยังคงอยู่
Composable บางรายการมีการรองรับในตัวสำหรับ Composable key
ตัวอย่างเช่น
LazyColumn
ยอมรับการระบุ key
ที่กำหนดเองใน items
DSL
@Composable fun MoviesScreenLazy(movies: List<Movie>) { LazyColumn { items(movies, key = { movie -> movie.id }) { movie -> MovieOverview(movie) } } }
ข้ามหากอินพุตไม่มีการเปลี่ยนแปลง
ในระหว่างการจัดโครงสร้างใหม่ ฟังก์ชัน Composable ที่มีสิทธิ์บางรายการสามารถมีฟังก์ชัน ข้ามการดำเนินการทั้งหมดหากอินพุตไม่ได้เปลี่ยนแปลงจาก องค์ประกอบ
ฟังก์ชันที่ประกอบกันได้มีสิทธิ์ข้ามเว้นแต่ว่า
- ฟังก์ชันมีประเภทการแสดงผลที่ไม่ใช่
Unit
- ฟังก์ชันนี้จะมีคำอธิบายประกอบด้วย
@NonRestartableComposable
หรือ วันที่@NonSkippableComposable
- พารามิเตอร์ที่ต้องระบุเป็นประเภทที่ไม่เสถียร
มีโหมดคอมไพเลอร์เวอร์ชันทดลอง นั่นคือการข้ามแบบเข้มงวด ซึ่งช่วยลดข้อกำหนดสุดท้าย
หากต้องการให้ระบบถือว่าประเภทเสถียรประเภทนั้น ประเภทนั้นต้องเป็นไปตามข้อกำหนดต่อไปนี้ สัญญา:
- ผลลัพธ์ของ
equals
สำหรับ 2 อินสแตนซ์จะตลอดไปเหมือนเดิมสำหรับ อินสแตนซ์สองตัวที่เหมือนกัน - หากพร็อพเพอร์ตี้สาธารณะของประเภทมีการเปลี่ยนแปลง ระบบจะแจ้งเตือนการเรียบเรียง
- นอกจากนี้ พร็อพเพอร์ตี้สาธารณะทุกประเภทก็มีความเสถียรด้วย
มีประเภททั่วไปที่สำคัญจำนวนหนึ่งในสัญญานี้ที่
คอมไพเลอร์ของการเขียนจะถือว่ามีความเสถียร แม้ว่าจะไม่มีการกำหนดอย่างชัดแจ้ง
ทำเครื่องหมายว่าเสถียรแล้วโดยใช้คำอธิบายประกอบ @Stable
:
- ประเภทค่าพื้นฐานทั้งหมด ได้แก่
Boolean
,Int
,Long
,Float
,Char
เป็นต้น - เครื่องสาย
- ฟังก์ชันทุกประเภท (lambda)
ทุกประเภทเหล่านี้สามารถทำตาม สัญญาคงที่เนื่องจาก เปลี่ยนแปลงไม่ได้ เนื่องจากประเภทที่เปลี่ยนแปลงไม่ได้ไม่เคยมีการเปลี่ยนแปลง จึงไม่มีความจำเป็นที่จะต้องแจ้งเตือนเลย องค์ประกอบการเปลี่ยนแปลง ทำให้ทำตามสัญญานี้ได้ง่ายขึ้น
ประเภทที่โดดเด่นอย่างหนึ่งที่มีความเสถียรแต่เปลี่ยนแปลงได้คือ MutableState
ของ Compose
ประเภท หากมีค่าอยู่ใน MutableState
ออบเจ็กต์สถานะโดยรวมจะเป็น
ถือว่าเสถียรเพราะ Compose จะได้รับการแจ้งเตือนเมื่อมีการเปลี่ยนแปลงเกิดขึ้นกับ
พร็อพเพอร์ตี้ .value
ของ State
เมื่อมีการส่งทุกประเภทเป็นพารามิเตอร์ไปยัง Composable มีค่าคงที่ พารามิเตอร์ ระบบจะเปรียบเทียบค่าเพื่อความเท่าเทียมตามตำแหน่งที่ Composable ใน UI ต้นไม้ ระบบจะข้ามการจัดองค์ประกอบใหม่หากค่าทั้งหมดไม่มีการเปลี่ยนแปลงตั้งแต่ การโทรก่อนหน้า
การเขียนจะพิจารณาประเภทไฟล์ที่เสถียรก็ต่อเมื่อพิสูจน์ได้ ตัวอย่างเช่น อินเทอร์เฟซมักถือว่าไม่เสถียร และประเภทที่มี "สาธารณะ" ที่เปลี่ยนแปลงได้ พร็อพเพอร์ตี้ที่การติดตั้งใช้งานอาจเปลี่ยนแปลงไม่ได้ก็ไม่เสถียรเช่นกัน
หาก Compose อนุมานไม่ได้ว่าประเภทนั้นเสถียร แต่ต้องการบังคับ
เขียนเพื่อทำให้ Chrome เสถียร ให้ทำเครื่องหมายด้วย
@Stable
// Marking the type as stable to favor skipping and smart recompositions. @Stable interface UiState<T : Result<T>> { val value: T? val exception: Throwable? val hasError: Boolean get() = exception != null }
ในข้อมูลโค้ดข้างต้น เนื่องจาก UiState
เป็นอินเทอร์เฟซ Compose สามารถ
โดยปกติแล้วจะถือว่าประเภทนี้ไม่เสถียร โดยเพิ่ม @Stable
คุณจะบอก Compose ว่าประเภทนี้เสถียร ทำให้ Compose ต้องการ
การจัดองค์ประกอบใหม่อัจฉริยะ และยังหมายความว่า Compose จะจัดการกับ
การใช้งานจะเสถียรหากใช้อินเทอร์เฟซเป็นประเภทพารามิเตอร์
แนะนำสำหรับคุณ
- หมายเหตุ: ข้อความลิงก์จะแสดงเมื่อ JavaScript ปิดอยู่
- State และ Jetpack Compose
- ผลข้างเคียงใน Compose
- บันทึกสถานะ UI ใน Compose