ในแอปพลิเคชัน Compose ตำแหน่งที่คุณยก สถานะ UI ขึ้นอยู่กับว่าตรรกะ UI หรือตรรกะทางธุรกิจกำหนดให้ทำเช่นนั้นหรือไม่ เอกสารนี้จะอธิบายสถานการณ์หลัก 2 สถานการณ์
แนวทางปฏิบัติแนะนำ
คุณควรยกสถานะ UI ขึ้นไปยังบรรพบุรุษร่วมที่ต่ำที่สุด ระหว่าง Composable ทั้งหมดที่อ่านและเขียนสถานะดังกล่าว และควรเก็บสถานะไว้ใกล้กับตำแหน่งที่ใช้สถานะนั้นมากที่สุด โดยเจ้าของสถานะควรแสดงสถานะที่ไม่เปลี่ยนแปลงและเหตุการณ์ต่างๆ ให้ผู้ใช้แก้ไขสถานะได้
บรรพบุรุษร่วมที่ต่ำที่สุดอาจอยู่นอกการจัดองค์ประกอบด้วย เช่น เมื่อยกสถานะขึ้นใน ViewModel เนื่องจากมีตรรกะทางธุรกิจเข้ามาเกี่ยวข้อง
หน้านี้จะอธิบายแนวทางปฏิบัติแนะนำนี้โดยละเอียด รวมถึงข้อควรระวังที่ควรทราบ
ประเภทของสถานะ UI และตรรกะ UI
ด้านล่างนี้คือคำจำกัดความของประเภทสถานะและตรรกะ UI ที่ใช้ในเอกสารนี้
สถานะ UI
สถานะ UI คือพร็อพเพอร์ตี้ที่ อธิบาย UI สถานะ UI มี 2 ประเภท ได้แก่
- สถานะ UI ของหน้าจอ คือ สิ่งที่ คุณต้องแสดงบนหน้าจอ ตัวอย่างเช่น คลาส
NewsUiStateอาจมีบทความข่าวและข้อมูลอื่นๆ ที่จำเป็นต่อการแสดงผล UI สถานะนี้มักจะเชื่อมโยงกับเลเยอร์อื่นๆ ในลำดับชั้นเนื่องจากมีข้อมูลแอป - สถานะองค์ประกอบ UI หมายถึงพร็อพเพอร์ตี้ที่ฝังอยู่ในองค์ประกอบ UI ซึ่งส่งผลต่อวิธีแสดงผล องค์ประกอบ UI อาจแสดงหรือซ่อน และอาจมีแบบอักษร ขนาดแบบอักษร หรือสีแบบอักษรที่เฉพาะเจาะจง ใน Jetpack Compose สถานะจะอยู่นอก Composable และคุณยังสามารถยกสถานะออกจากบริเวณใกล้เคียงของ Composable ได้ไปยังฟังก์ชัน Composable ที่เรียกใช้หรือตัวเก็บสถานะ ตัวอย่างของสถานะนี้คือ
ScaffoldStateสำหรับScaffoldคอมโพสได้
ตรรกะ
ตรรกะในแอปพลิเคชันอาจเป็นตรรกะทางธุรกิจหรือตรรกะ UI
- ตรรกะทางธุรกิจ คือการใช้งานข้อกำหนดของผลิตภัณฑ์สำหรับข้อมูลแอป เช่น การเพิ่มบทความลงในบุ๊กมาร์กในแอปอ่านข่าวเมื่อผู้ใช้แตะปุ่ม โดยปกติแล้วตรรกะในการบันทึกบุ๊กมาร์กลงในไฟล์หรือฐานข้อมูลจะอยู่ในเลเยอร์โดเมนหรือเลเยอร์ข้อมูล ตัวเก็บสถานะมักจะมอบหมายตรรกะนี้ไปยังเลเยอร์เหล่านั้นโดยการเรียกใช้เมธอดที่เลเยอร์เหล่านั้นแสดง
- ตรรกะ UI เกี่ยวข้องกับ วิธี แสดงสถานะ UI บนหน้าจอ เช่น การรับคำแนะนำที่เหมาะสมสำหรับแถบค้นหาเมื่อผู้ใช้เลือกหมวดหมู่ การเลื่อนไปยังรายการที่เฉพาะเจาะจงในรายการ หรือตรรกะการนำทางไปยังหน้าจอที่เฉพาะเจาะจงเมื่อผู้ใช้คลิกปุ่ม
ตรรกะ UI
เมื่อ ตรรกะ UI ต้องอ่านหรือเขียนสถานะ คุณควรจำกัดขอบเขตสถานะไว้ที่ UI ตามวงจรการทำงานของ UI หากต้องการทำเช่นนี้ คุณควรยกสถานะขึ้นในระดับที่ถูกต้องในฟังก์ชันที่ประกอบกันได้ หรือจะทำในคลาสตัวเก็บสถานะธรรมดาที่จำกัดขอบเขตไว้ที่วงจรการทำงานของ UI ก็ได้
ด้านล่างนี้คือคำอธิบายของโซลูชันทั้ง 2 รายการและคำอธิบายเกี่ยวกับเวลาที่จะใช้โซลูชันใด
คอมโพสได้เป็นเจ้าของสถานะ
การมีตรรกะ UI และสถานะองค์ประกอบ UI ในคอมโพสได้เป็นแนวทางที่ดีหากสถานะและตรรกะมีความซับซ้อนไม่มาก คุณสามารถเก็บสถานะไว้ภายในคอมโพสได้หรือยกสถานะขึ้นตามที่จำเป็น
ไม่จำเป็นต้องย้ายสถานะ
การยกสถานะขึ้นไม่จำเป็นเสมอไป คุณสามารถเก็บสถานะไว้ภายในคอมโพสได้เมื่อไม่มีคอมโพสได้อื่นๆ ที่ต้องควบคุมสถานะนั้น ในข้อมูลโค้ดนี้มีคอมโพสได้ที่ขยายและยุบเมื่อแตะ
@Composable fun ChatBubble( message: Message ) { var showDetails by rememberSaveable { mutableStateOf(false) } // Define the UI element expanded state Text( text = AnnotatedString(message.content), modifier = Modifier.clickable { showDetails = !showDetails // Apply UI logic } ) if (showDetails) { Text(message.timestamp) } }
ตัวแปร showDetails คือสถานะภายในขององค์ประกอบ UI นี้ โดยจะอ่านและแก้ไขในคอมโพสได้นี้เท่านั้น และตรรกะที่ใช้กับตัวแปรนี้ก็มีความซับซ้อนไม่มาก
ดังนั้นการยกสถานะขึ้นในกรณีนี้จึงไม่เป็นประโยชน์มากนัก คุณจึงเก็บสถานะไว้ภายในได้ การทำเช่นนี้จะทำให้คอมโพสได้นี้เป็นเจ้าของและแหล่งข้อมูลเดียวที่เชื่อถือได้ของสถานะที่ขยาย
การยกสถานะขึ้นภายในคอมโพสได้
หากต้องการแชร์สถานะองค์ประกอบ UI กับคอมโพสได้อื่นๆ และใช้ตรรกะ UI กับสถานะนั้นในที่ต่างๆ คุณสามารถยกสถานะขึ้นไปในระดับที่สูงขึ้นในลำดับชั้น UI นอกจากนี้ยังทำให้คอมโพสได้ของคุณนำกลับมาใช้ซ้ำได้มากขึ้นและทดสอบได้ง่ายขึ้น
ตัวอย่างต่อไปนี้เป็นแอปแชทที่ใช้ฟังก์ชันการทำงาน 2 อย่าง
- ปุ่ม
JumpToBottomจะเลื่อนรายการข้อความลงไปที่ด้านล่าง ปุ่มนี้ใช้ตรรกะ UI กับสถานะรายการ - รายการ
MessagesListจะเลื่อนลงไปที่ด้านล่างหลังจากที่ผู้ใช้ส่งข้อความใหม่ UserInput ใช้ตรรกะ UI กับสถานะรายการ
JumpToBottom และเลื่อนลงไปที่ด้านล่างเมื่อมีข้อความใหม่ลำดับชั้นของคอมโพสได้มีดังนี้
สถานะ LazyColumn จะถูกยกขึ้นไปยังหน้าจอการสนทนาเพื่อให้แอปใช้ตรรกะ UI และอ่านสถานะจาก Composable ได้ทั้งหมดที่ต้องใช้สถานะนั้นได้
LazyColumn จาก LazyColumn ไปยัง ConversationScreenดังนั้นคอมโพสได้สุดท้ายจึงมีลักษณะดังนี้
LazyListState ยกขึ้นไปยัง ConversationScreenโค้ดมีลักษณะดังนี้
@Composable private fun ConversationScreen(/*...*/) { val scope = rememberCoroutineScope() val lazyListState = rememberLazyListState() // State hoisted to the ConversationScreen MessagesList(messages, lazyListState) // Reuse same state in MessageList UserInput( onMessageSent = { // Apply UI logic to lazyListState scope.launch { lazyListState.scrollToItem(0) } }, ) } @Composable private fun MessagesList( messages: List<Message>, lazyListState: LazyListState = rememberLazyListState() // LazyListState has a default value ) { LazyColumn( state = lazyListState // Pass hoisted state to LazyColumn ) { items(messages, key = { message -> message.id }) { item -> Message(/*...*/) } } val scope = rememberCoroutineScope() JumpToBottom(onClicked = { scope.launch { lazyListState.scrollToItem(0) // UI logic being applied to lazyListState } }) }
LazyListState จะถูกยกขึ้นไปสูงเท่าที่จำเป็นสำหรับตรรกะ UI ที่ต้องใช้ เนื่องจากมีการเริ่มต้นในฟังก์ชันที่ประกอบกันได้ ระบบจึงจัดเก็บไว้ในการจัดองค์ประกอบตามวงจรการทำงาน
โปรดทราบว่า lazyListState กำหนดไว้ในเมธอด MessagesList โดยมีค่าเริ่มต้นเป็น rememberLazyListState() ซึ่งเป็นรูปแบบที่ใช้กันทั่วไปใน Compose
และทำให้คอมโพสได้นำกลับมาใช้ซ้ำได้มากขึ้นและมีความยืดหยุ่นมากขึ้น จากนั้นคุณจะใช้คอมโพสได้ในส่วนต่างๆ ของแอปที่ไม่จำเป็นต้องควบคุมสถานะได้ ซึ่งมักจะเป็นกรณีที่เกิดขึ้นขณะทดสอบหรือแสดงตัวอย่างคอมโพสได้ LazyColumn กำหนดสถานะในลักษณะนี้
LazyListState คือ ConversationScreenคลาสตัวเก็บสถานะธรรมดาเป็นเจ้าของสถานะ
เมื่อ Composable มีตรรกะ UI ที่ซับซ้อนซึ่งเกี่ยวข้องกับฟิลด์สถานะอย่างน้อย 1 รายการขององค์ประกอบ UI คอมโพสได้นั้นควรมอบหมายความรับผิดชอบดังกล่าวให้กับตัวเก็บสถานะ เช่น คลาสตัวเก็บสถานะธรรมดา ซึ่งจะทำให้ตรรกะของคอมโพสได้ทดสอบได้ง่ายขึ้นและลดความซับซ้อนลง แนวทางนี้สนับสนุน หลักการแยกความกังวลออกจากกัน: Composable มีหน้าที่ ในการปล่อยองค์ประกอบ UI และตัวเก็บสถานะมีตรรกะ UI และสถานะองค์ประกอบ UI
คลาสตัวเก็บสถานะธรรมดามีฟังก์ชันที่สะดวกสำหรับผู้เรียกใช้ฟังก์ชันที่ประกอบกันได้ คุณจึงไม่จำเป็นต้องเขียนตรรกะนี้เอง
ระบบจะสร้างและจดจำคลาสธรรมดาเหล่านี้ในการจัดองค์ประกอบ เนื่องจากคลาสเหล่านี้
เป็นไปตามวงจรการทำงานของคอมโพสได้ จึงใช้ประเภทที่ไลบรารี
Compose มีให้ได้ เช่น rememberNavController() หรือ rememberLazyListState()
ตัวอย่างของคลาสนี้คือ LazyListState ตัวเก็บสถานะธรรมดา
คลาส ซึ่งใช้ใน Compose เพื่อควบคุมความซับซ้อนของ UI ของ LazyColumn
หรือ LazyRow
// LazyListState.kt @Stable class LazyListState constructor( firstVisibleItemIndex: Int = 0, firstVisibleItemScrollOffset: Int = 0 ) : ScrollableState { /** * The holder class for the current scroll position. */ private val scrollPosition = LazyListScrollPosition( firstVisibleItemIndex, firstVisibleItemScrollOffset ) suspend fun scrollToItem(/*...*/) { /*...*/ } override suspend fun scroll() { /*...*/ } suspend fun animateScrollToItem() { /*...*/ } }
LazyListState ห่อหุ้มสถานะของ LazyColumn โดยจัดเก็บ
scrollPosition สำหรับองค์ประกอบ UI นี้ นอกจากนี้ยังแสดงเมธอดเพื่อแก้ไขตำแหน่งการเลื่อน เช่น การเลื่อนไปยังรายการที่ระบุ
คุณจะเห็นว่าการเพิ่มความรับผิดชอบของ Composable จะเพิ่ม ความจำเป็นในการใช้ตัวเก็บสถานะ ความรับผิดชอบอาจอยู่ในตรรกะ UI หรือเพียงแค่จำนวนสถานะที่ต้องติดตาม
อีกรูปแบบที่ใช้กันทั่วไปคือการใช้คลาสตัวเก็บสถานะธรรมดาเพื่อจัดการความซับซ้อนของฟังก์ชันที่ประกอบกันได้ระดับรากในแอป คุณสามารถใช้คลาสดังกล่าวเพื่อห่อหุ้มสถานะระดับแอป เช่น สถานะการนำทางและการปรับขนาดหน้าจอ ดูคำอธิบายทั้งหมด ได้ในหน้าตรรกะ UI และตัวเก็บสถานะ
ตรรกะทางธุรกิจ
หาก Composable และคลาสตัวเก็บสถานะธรรมดามีหน้าที่รับผิดชอบตรรกะ UI และสถานะองค์ประกอบ UI ตัวเก็บสถานะระดับหน้าจอจะมีหน้าที่รับผิดชอบงานต่อไปนี้
- ให้สิทธิ์เข้าถึงตรรกะทางธุรกิจของแอปพลิเคชัน ซึ่งโดยปกติแล้วจะอยู่ในเลเยอร์อื่นๆ ในลำดับชั้น เช่น เลเยอร์ธุรกิจและ เลเยอร์ข้อมูล
- เตรียมข้อมูลแอปพลิเคชันสำหรับการนำเสนอในหน้าจอที่เฉพาะเจาะจง ซึ่งจะกลายเป็นสถานะ UI ของหน้าจอ
ViewModel เป็นเจ้าของสถานะ
สิทธิประโยชน์ของ AAC ViewModel ในการพัฒนา Android ทำให้ ViewModel เหมาะสมสำหรับการให้สิทธิ์เข้าถึงตรรกะทางธุรกิจและการเตรียมข้อมูลแอปพลิเคชันสำหรับการนำเสนอบนหน้าจอ
เมื่อยกสถานะ UI ขึ้นใน ViewModel คุณจะย้ายสถานะนั้นออกจากการจัดองค์ประกอบ
ViewModel จะจัดเก็บไว้นอกการจัดองค์ประกอบระบบจะไม่จัดเก็บ ViewModel เป็นส่วนหนึ่งของการจัดองค์ประกอบ โดยเฟรมเวิร์กจะเป็นผู้จัดหา ViewModel และ ViewModel จะจำกัดขอบเขตไว้ที่ ViewModelStoreOwner ซึ่งอาจเป็น
Activity, Fragment, กราฟการนำทาง หรือปลายทางของกราฟการนำทาง ดูข้อมูลเพิ่มเติมเกี่ยวกับขอบเขต
ViewModelได้จากเอกสารประกอบ
จากนั้น ViewModel จะเป็นแหล่งข้อมูลเดียวที่เชื่อถือได้และบรรพบุรุษร่วมที่ต่ำที่สุด สำหรับสถานะ UI
สถานะ UI ของหน้าจอ
ตามคำจำกัดความข้างต้น สถานะ UI ของหน้าจอเกิดจากการใช้กฎทางธุรกิจ เนื่องจากตัวเก็บสถานะระดับหน้าจอมีหน้าที่รับผิดชอบสถานะ UI ของหน้าจอ ซึ่งหมายความว่าโดยปกติแล้วสถานะ UI ของหน้าจอจะถูกยกขึ้นในตัวเก็บสถานะระดับหน้าจอ ซึ่งในกรณีนี้คือ ViewModel
พิจารณา ConversationViewModel ของแอปแชทและวิธีที่ ViewModel แสดงสถานะ UI ของหน้าจอและเหตุการณ์ต่างๆ เพื่อแก้ไขสถานะดังกล่าว
class ConversationViewModel( channelId: String, messagesRepository: MessagesRepository ) : ViewModel() { val messages = messagesRepository .getLatestMessages(channelId) .stateIn( scope = viewModelScope, started = SharingStarted.WhileSubscribed(5_000), initialValue = emptyList() ) // Business logic fun sendMessage(message: Message) { /* ... */ } }
คอมโพสได้ใช้สถานะ UI ของหน้าจอที่ยกขึ้นใน ViewModel คุณควรแทรกอินสแตนซ์ ViewModel ในคอมโพสได้ระดับหน้าจอเพื่อให้สิทธิ์เข้าถึงตรรกะทางธุรกิจ
ต่อไปนี้เป็นตัวอย่างของ ViewModel ที่ใช้ในคอมโพสได้ระดับหน้าจอ
ในตัวอย่างนี้ คอมโพสได้ ConversationScreen() ใช้สถานะ UI ของหน้าจอที่ยกขึ้นใน ViewModel
@Composable private fun ConversationScreen( conversationViewModel: ConversationViewModel = viewModel() ) { val messages by conversationViewModel.messages.collectAsStateWithLifecycle() ConversationScreen( messages = messages, onSendMessage = { message: Message -> conversationViewModel.sendMessage(message) } ) } @Composable private fun ConversationScreen( messages: List<Message>, onSendMessage: (Message) -> Unit ) { MessagesList(messages, onSendMessage) /* ... */ }
การส่งต่อพร็อพเพอร์ตี้
"การส่งต่อพร็อพเพอร์ตี้" หมายถึงการส่งข้อมูลผ่านคอมโพเนนต์ย่อยที่ซ้อนกันหลายรายการไปยังตำแหน่งที่จะอ่านข้อมูลนั้น
ตัวอย่างทั่วไปที่การส่งต่อพร็อพเพอร์ตี้อาจปรากฏใน Compose คือเมื่อคุณแทรกตัวเก็บสถานะระดับหน้าจอที่ระดับบนสุดและส่งสถานะและเหตุการณ์ต่างๆ ไปยัง Composable ย่อย ซึ่งอาจทำให้เกิดการโอเวอร์โหลดลายเซ็นของฟังก์ชันคอมโพสได้ด้วย
แม้ว่าการแสดงเหตุการณ์เป็นพารามิเตอร์แลมดาแต่ละรายการอาจทำให้ลายเซ็นของฟังก์ชันโอเวอร์โหลด แต่ก็ช่วยให้มองเห็นความรับผิดชอบของฟังก์ชันที่ประกอบกันได้ชัดเจนที่สุด คุณจะเห็นสิ่งที่ฟังก์ชันทำได้อย่างรวดเร็ว
การส่งต่อพร็อพเพอร์ตี้เป็นวิธีที่แนะนำมากกว่าการสร้างคลาส Wrapper เพื่อห่อหุ้มสถานะและเหตุการณ์ต่างๆ ไว้ในที่เดียว เนื่องจากวิธีนี้จะลดการมองเห็นความรับผิดชอบของคอมโพสได้ การไม่ใช้คลาส Wrapper ยังช่วยให้คุณส่งเฉพาะพารามิเตอร์ที่คอมโพสได้ต้องการ ซึ่งเป็นแนวทางปฏิบัติแนะนำ
แนวทางปฏิบัติแนะนำเดียวกันนี้ใช้ได้หากเหตุการณ์เหล่านี้เป็นเหตุการณ์การนำทาง คุณสามารถ ดูข้อมูลเพิ่มเติมเกี่ยวกับเรื่องนี้ได้ในเอกสารประกอบการนำทาง
หากพบปัญหาด้านประสิทธิภาพ คุณอาจเลือกที่จะเลื่อนการอ่านสถานะออกไป ดูข้อมูลเพิ่มเติมได้ในเอกสารประกอบด้านประสิทธิภาพ
สถานะองค์ประกอบ UI
คุณสามารถยกสถานะองค์ประกอบ UI ขึ้นไปยังตัวเก็บสถานะระดับหน้าจอได้หากมีตรรกะทางธุรกิจที่ต้องอ่านหรือเขียนสถานะนั้น
จากตัวอย่างแอปแชท แอปจะแสดงคำแนะนำผู้ใช้ในการแชทเป็นกลุ่มเมื่อผู้ใช้พิมพ์ @ และคำแนะนำ คำแนะนำเหล่านั้นมาจากเลเยอร์ข้อมูล และตรรกะในการคำนวณรายการคำแนะนำผู้ใช้ถือเป็นตรรกะทางธุรกิจ ฟีเจอร์นี้มีลักษณะดังนี้
@ และคำแนะนำViewModel ที่ใช้ฟีเจอร์นี้จะมีลักษณะดังนี้
class ConversationViewModel(/*...*/) : ViewModel() { // Hoisted state var inputMessage by mutableStateOf("") private set val suggestions: StateFlow<List<Suggestion>> = snapshotFlow { inputMessage } .filter { hasSocialHandleHint(it) } .mapLatest { getHandle(it) } .mapLatest { repository.getSuggestions(it) } .stateIn( scope = viewModelScope, started = SharingStarted.WhileSubscribed(5_000), initialValue = emptyList() ) fun updateInput(newInput: String) { inputMessage = newInput } }
inputMessage เป็นตัวแปรที่จัดเก็บสถานะ TextField ทุกครั้งที่ผู้ใช้พิมพ์ข้อมูลใหม่ แอปจะเรียกใช้ตรรกะทางธุรกิจเพื่อสร้าง suggestions
suggestions คือสถานะ UI ของหน้าจอและใช้จาก Compose UI โดยการรวบรวม
จาก StateFlow
ข้อควรระวัง
สำหรับสถานะองค์ประกอบ UI บางอย่างของ Compose การยกสถานะขึ้นไปยัง ViewModel อาจต้องพิจารณาเป็นพิเศษ เช่น ตัวเก็บสถานะบางตัวขององค์ประกอบ UI ของ Compose แสดงเมธอดเพื่อแก้ไขสถานะ โดยบางเมธอดอาจเป็นฟังก์ชันระงับที่ทริกเกอร์ภาพเคลื่อนไหว ฟังก์ชันระงับเหล่านี้อาจแสดงข้อยกเว้นหากคุณเรียกใช้
จาก CoroutineScope ที่ไม่ได้จำกัดขอบเขตไว้ที่การจัดองค์ประกอบ
สมมติว่าเนื้อหาของลิ้นชักแอปเป็นแบบไดนามิก และคุณต้องดึงข้อมูลและรีเฟรชเนื้อหาจากเลเยอร์ข้อมูลหลังจากปิดลิ้นชักแล้ว คุณควรยกสถานะลิ้นชักขึ้นไปยัง ViewModel เพื่อให้คุณเรียกใช้ทั้งตรรกะ UI และตรรกะทางธุรกิจในองค์ประกอบนี้จากเจ้าของสถานะได้
อย่างไรก็ตาม การเรียกใช้เมธอด close() ของ DrawerState โดยใช้
viewModelScope จาก Compose UI จะทำให้เกิดข้อยกเว้นรันไทม์ประเภท
IllegalStateException พร้อมข้อความว่า “a
MonotonicFrameClock is not available in this
CoroutineContext”.
หากต้องการแก้ไขปัญหานี้ ให้ใช้ CoroutineScope ที่จำกัดขอบเขตไว้ที่การจัดองค์ประกอบ ซึ่งจะให้ MonotonicFrameClock ใน CoroutineContext ที่จำเป็นต่อการทำงานของฟังก์ชันระงับ
หากต้องการแก้ไขข้อขัดข้องนี้ ให้เปลี่ยน CoroutineContext ของโครูทีนใน ViewModel เป็นโครูทีนที่จำกัดขอบเขตไว้ที่การจัดองค์ประกอบ ซึ่งอาจมีลักษณะดังนี้
class ConversationViewModel(/*...*/) : ViewModel() { val drawerState = DrawerState(initialValue = DrawerValue.Closed) private val _drawerContent = MutableStateFlow(DrawerContent.Empty) val drawerContent: StateFlow<DrawerContent> = _drawerContent.asStateFlow() fun closeDrawer(uiScope: CoroutineScope) { viewModelScope.launch { withContext(uiScope.coroutineContext) { // Use instead of the default context drawerState.close() } // Fetch drawer content and update state _drawerContent.update { content } } } } // in Compose @Composable private fun ConversationScreen( conversationViewModel: ConversationViewModel = viewModel() ) { val scope = rememberCoroutineScope() ConversationScreen(onCloseDrawer = { conversationViewModel.closeDrawer(uiScope = scope) }) }
ดูข้อมูลเพิ่มเติม
ดูข้อมูลเพิ่มเติมเกี่ยวกับสถานะและ Jetpack Compose ได้จากแหล่งข้อมูลเพิ่มเติมต่อไปนี้
ตัวอย่าง
Codelab
วิดีโอ
แนะนำสำหรับคุณ
- หมายเหตุ: ข้อความลิงก์จะแสดงเมื่อ JavaScript ปิดอยู่
- บันทึกสถานะ UI ใน Compose
- รายการและตารางกริด
- การออกแบบสถาปัตยกรรม UI ของ Compose