โครูทีน Kotlin มี API ที่ช่วยให้คุณเขียนโค้ดแบบอะซิงโครนัสได้ เมื่อใช้โครูทีนของ Kotlin คุณสามารถกำหนด CoroutineScope ซึ่งช่วยให้คุณจัดการเวลาที่โครูทีนควรทำงานได้ การดำเนินการแบบอะซิงโครนัสแต่ละรายการจะทำงานภายในขอบเขตที่เฉพาะเจาะจง
คอมโพเนนต์ที่รับรู้ถึงวงจรชีวิตให้การสนับสนุนระดับเฟิร์สคลาสสำหรับโครูทีนสำหรับขอบเขตเชิงตรรกะในแอป เอกสารนี้อธิบายวิธีใช้โครูทีนอย่างมีประสิทธิภาพกับคอมโพเนนต์ที่รับรู้ถึงวงจรชีวิต
เพิ่มทรัพยากร Dependency
ขอบเขตโครูทีนในตัวที่อธิบายไว้ในหัวข้อนี้จะอยู่ใน Lifecycle API อย่าลืมเพิ่มทรัพยากร Dependency ที่เหมาะสมเมื่อใช้ขอบเขตเหล่านี้
- สำหรับยูทิลิตี ViewModel ใน Compose ให้ใช้
implementation("androidx.lifecycle:lifecycle-viewmodel-compose:$lifecycle_version") - สำหรับยูทิลิตีวงจรใน Compose ให้ใช้
implementation("androidx.lifecycle:lifecycle-runtime-compose:$lifecycle_version")
ขอบเขต Coroutine ที่รับรู้วงจร
Compose และไลบรารีวงจรมีขอบเขตในตัวต่อไปนี้ที่คุณใช้ในแอปได้
ViewModelScope
ระบบจะกำหนด ViewModelScope สำหรับ ViewModel แต่ละรายการในแอปของคุณ ระบบจะยกเลิกโครูทีนที่เปิดใช้งานในขอบเขตนี้โดยอัตโนมัติหากมีการล้าง ViewModel โคโรทีนมีประโยชน์ในกรณีนี้เมื่อคุณมีงานที่ต้องทำเฉพาะเมื่อ ViewModel ทำงานอยู่เท่านั้น ตัวอย่างเช่น หากคุณกำลังคำนวณข้อมูลบางอย่างสำหรับเลย์เอาต์ คุณควรกำหนดขอบเขตงานให้กับ ViewModel เพื่อให้ระบบยกเลิกงานโดยอัตโนมัติหากมีการล้าง ViewModel เพื่อหลีกเลี่ยงการใช้ทรัพยากร
คุณเข้าถึง CoroutineScope ของ ViewModel ได้ผ่านพร็อพเพอร์ตี้ viewModelScope ของ ViewModel ดังที่แสดงในตัวอย่างต่อไปนี้
class MyViewModel: ViewModel() {
init {
viewModelScope.launch {
// Coroutine that will be canceled when the ViewModel is cleared.
}
}
}
สำหรับกรณีการใช้งานขั้นสูง คุณสามารถส่ง CoroutineScope ที่กำหนดเองไปยังคอนสตรัคเตอร์ของ ViewModel โดยตรงเพื่อแทนที่ viewModelScope เริ่มต้นได้ วิธีนี้ช่วยให้ควบคุมได้มากขึ้นและมีความยืดหยุ่นมากขึ้น โดยเฉพาะในกรณีต่อไปนี้
การทดสอบ: ช่วยให้คุณแทรก
TestScopeได้ ซึ่งช่วยให้ควบคุมเวลาและยืนยันลักษณะการทำงานของโครูทีนใน Unit Test ได้ง่ายขึ้นการกำหนดค่าที่กำหนดเอง: คุณสามารถกำหนดค่าขอบเขตด้วย
CoroutineDispatcherที่เฉพาะเจาะจง (เช่นDispatchers.Defaultสำหรับการคำนวณที่หนักหน่วง) หรือCoroutineExceptionHandlerที่กำหนดเองก่อนที่ ViewModel จะเริ่มทำงานได้
ขอบเขตที่เชื่อมโยงกับองค์ประกอบ
ผลข้างเคียง เช่น ภาพเคลื่อนไหว การเรียกใช้เครือข่าย หรือตัวจับเวลาต้องกำหนดขอบเขตให้อยู่ในวงจรของ Composable ด้วยวิธีนี้ เมื่อ Composable ออกจากหน้าจอ (ออกจาก Composition) ระบบจะยกเลิกโครูทีนที่ทำงานอยู่โดยอัตโนมัติเพื่อป้องกันไม่ให้หน่วยความจำรั่วไหล
Compose มี LaunchedEffect API เพื่อจัดการการกำหนดขอบเขต Composition แบบประกาศ
LaunchedEffect จะสร้าง CoroutineScope ที่ช่วยให้คุณเรียกใช้ฟังก์ชันระงับได้ ขอบเขตจะเชื่อมโยงกับวงจร Composition ของ Composable ไม่ใช่
วงจรของกิจกรรมโฮสต์
- Enter: โครูทีนจะเริ่มเมื่อ Composable เข้าสู่ Composition
- ออก: ระบบจะยกเลิกโครูทีนเมื่อ Composable ออกจาก Composition
- เปิดอีกครั้ง: หากคีย์ที่ส่งไปยัง
LaunchedEffectมีการเปลี่ยนแปลง ระบบจะยกเลิกโครูทีนที่มีอยู่และเปิดโครูทีนใหม่
ตัวอย่างต่อไปนี้แสดงวิธีใช้ LaunchedEffect เพื่อสร้างภาพเคลื่อนไหวแบบพัลส์ โครูทีนจะเชื่อมโยงกับการมีอยู่ของ Composable ในองค์ประกอบและตอบสนองต่อการเปลี่ยนแปลงการกำหนดค่า ดังนี้
// Allow the pulse rate to be configured, so it can be sped up if the user is running // out of time var pulseRateMs by remember { mutableLongStateOf(3000L) } val alpha = remember { Animatable(1f) } LaunchedEffect(pulseRateMs) { // Restart the effect when the pulse rate changes while (isActive) { delay(pulseRateMs) // Pulse the alpha every pulseRateMs to alert the user alpha.animateTo(0f) alpha.animateTo(1f) } }
ดูข้อมูลเพิ่มเติมเกี่ยวกับ LaunchedEffect ได้ที่ผลข้างเคียงใน Compose
คอลเล็กชันโฟลว์ที่รับรู้ถึงวงจรชีวิต
หากต้องการรวบรวมโฟลว์ใน Jetpack Compose อย่างปลอดภัย ให้ใช้ API collectAsStateWithLifecycle ฟังก์ชันเดียวนี้จะแปลง Flow เป็นออบเจ็กต์ Compose State และจัดการการสมัครรับข้อมูลวงจรให้คุณโดยอัตโนมัติ โดยค่าเริ่มต้น การรวบรวมจะเริ่มขึ้นเมื่อวงจรเป็น STARTED และหยุดเมื่อวงจรเป็น STOPPED หากต้องการลบล้างลักษณะการทำงานเริ่มต้นนี้ ให้ส่งพารามิเตอร์ minActiveState พร้อมเมธอดวงจรที่ต้องการ เช่น Lifecycle.State.RESUMED
ตัวอย่างต่อไปนี้แสดงวิธีรวบรวม StateFlow ของ ViewModel ใน Composable
@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 คุณสามารถรวบรวมหลายโฟลว์พร้อมกันได้โดยประกาศตัวแปรสถานะหลายรายการ เนื่องจาก collectAsStateWithLifecycle จัดการขอบเขตที่สำคัญของตัวเอง การรวบรวมข้อมูลแบบคู่ขนานจึงได้รับการจัดการโดยอัตโนมัติ ดังนี้
@Composable
fun DashboardScreen(viewModel: DashboardViewModel = viewModel()) {
// Both flows are collected safely in parallel and will emit updates when either changes, the composables will recompose
val userData by viewModel.userFlow.collectAsStateWithLifecycle()
val feedData by viewModel.feedFlow.collectAsStateWithLifecycle()
// ...
}
คำนวณค่าแบบอะซิงโครนัสโดยใช้ Flows
เมื่อต้องการคำนวณค่าแบบอะซิงโครนัส ให้ใช้ StateFlow กับโอเปอเรเตอร์ stateIn
ข้อมูลโค้ดต่อไปนี้ใช้ Flow มาตรฐานที่แปลงเป็น StateFlow พารามิเตอร์ WhileSubscribed(5000) จะทำให้การสมัครใช้บริการทำงานต่อไปเป็นเวลา 5 วินาทีหลังจากที่ UI หายไปเพื่อจัดการกับการเปลี่ยนแปลงการกำหนดค่า
val uiState: StateFlow<Result> = flow {
emit(repository.fetchData())
}
.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5_000),
initialValue = Result.Loading
)
ใช้ collectAsStateWithLifecycle เพื่อแปลงค่าที่รวบรวมไว้เป็น Compose State เพื่อให้ UI อัปเดตตามปฏิกิริยาเมื่อข้อมูลมีการเปลี่ยนแปลง
ดูข้อมูลเพิ่มเติมเกี่ยวกับสถานะได้ที่สถานะและ Jetpack Compose
แหล่งข้อมูลเพิ่มเติม
ดูเนื้อหา
ตัวอย่าง
แนะนำสำหรับคุณ
- หมายเหตุ: ข้อความลิงก์จะแสดงเมื่อ JavaScript ปิดอยู่
- การจัดการวงจรด้วยคอมโพเนนต์ที่รับรู้วงจร
- โหลดและแสดงข้อมูลแบบแบ่งหน้า