Kotlin Coroutines มี API ที่ช่วยให้คุณเขียนโค้ดแบบอะซิงโครนัสได้
เมื่อใช้โครูทีน Kotlin คุณจะกำหนด CoroutineScope ซึ่งช่วยให้คุณจัดการเวลาที่โครูทีนควรทำงานได้ การดำเนินการแบบไม่พร้อมกันแต่ละรายการ
จะทำงานภายในขอบเขตที่เฉพาะเจาะจง
คอมโพเนนต์ที่รับรู้ถึงวงจรของแอปให้การรองรับโครูทีนระดับเฟิร์สคลาสสำหรับ ขอบเขตเชิงตรรกะในแอป เอกสารนี้อธิบายวิธีใช้โครูทีน อย่างมีประสิทธิภาพกับคอมโพเนนต์ที่รับรู้ถึงวงจรของแอป
เพิ่มทรัพยากร Dependency
ขอบเขตของโครูทีนในตัวที่อธิบายไว้ในหัวข้อนี้จะอยู่ใน Lifecycle API อย่าลืมเพิ่มการอ้างอิงที่เหมาะสมเมื่อใช้ขอบเขตเหล่านี้
- สำหรับยูทิลิตี ViewModel ใน Compose ให้ใช้
implementation("androidx.lifecycle:lifecycle-viewmodel-compose:$lifecycle_version") - สำหรับยูทิลิตีวงจรใน Compose ให้ใช้
implementation("androidx.lifecycle:lifecycle-runtime-compose:$lifecycle_version")
ขอบเขตของโครูทีนที่รับรู้ถึงวงจร
ไลบรารี Compose และ Lifecycle มีขอบเขตในตัวต่อไปนี้ที่คุณใช้ในแอปได้
ViewModelScope
ViewModelScope จะกำหนดไว้สำหรับ ViewModel แต่ละรายการในแอปของคุณ
Coroutine ที่เปิดใช้ในขอบเขตนี้จะถูกยกเลิกโดยอัตโนมัติหากมีการล้าง ViewModel Coroutine มีประโยชน์ในกรณีที่คุณมีงานที่ต้องทำเมื่อ ViewModel ทำงานอยู่เท่านั้น เช่น หากคุณกำลังประมวลผลข้อมูลบางอย่าง
สำหรับเลย์เอาต์ คุณควรจำกัดขอบเขตงานไว้ใน ViewModel เพื่อให้ระบบยกเลิกงานโดยอัตโนมัติหากมีการล้าง ViewModel เพื่อหลีกเลี่ยงการใช้
ทรัพยากร
คุณเข้าถึง CoroutineScope ของ ViewModel ได้ผ่านพร็อพเพอร์ตี้ viewModelScope ของ ViewModel ดังที่แสดงในตัวอย่างต่อไปนี้
class MyViewModel: ViewModel() {
init {
viewModelScope.launch {
// Coroutine that will be canceled when the ViewModel is cleared.
}
}
}
สำหรับ Use Case ขั้นสูง คุณสามารถส่ง CoroutineScope ที่กำหนดเองโดยตรง
ไปยังตัวสร้างของ ViewModel เพื่อแทนที่ viewModelScope เริ่มต้นได้ แนวทางนี้ช่วยให้ควบคุมและมีความยืดหยุ่นมากขึ้น โดยเฉพาะในกรณีต่อไปนี้
การทดสอบ: ช่วยให้คุณแทรก
TestScopeได้ ทำให้ควบคุมเวลาได้ง่ายขึ้น และยืนยันลักษณะการทำงานของโครูทีนในการทดสอบหน่วยได้การกำหนดค่าที่กำหนดเอง: คุณกำหนดค่าขอบเขตด้วย
CoroutineDispatcherที่เฉพาะเจาะจง (เช่นDispatchers.Defaultสำหรับการคำนวณที่ซับซ้อน) หรือCoroutineExceptionHandlerที่กำหนดเองก่อนที่ ViewModel จะเริ่มทำงานได้
ขอบเขตที่เชื่อมโยงกับองค์ประกอบ
ผลข้างเคียง เช่น ภาพเคลื่อนไหว การเรียกเครือข่าย หรือตัวจับเวลา ต้องกำหนดขอบเขตตาม วงจรของ Composable ด้วยวิธีนี้ เมื่อ Composable ออกจากหน้าจอ (ออกจาก Composition) ระบบจะยกเลิก Coroutine ที่กำลังทำงานโดยอัตโนมัติเพื่อป้องกันไม่ให้เกิดหน่วยความจำรั่ว
Compose มี API LaunchedEffect เพื่อจัดการการกำหนดขอบเขตของ Composition โดยใช้การประกาศ
LaunchedEffect สร้าง CoroutineScope ที่ช่วยให้คุณเรียกใช้ฟังก์ชันระงับได้ ขอบเขตจะเชื่อมโยงกับวงจรการเรียบเรียงเพลงของ Composable ไม่ใช่
วงจรของกิจกรรมโฮสต์
- เข้าสู่: โครูทีนจะเริ่มเมื่อ Composable เข้าสู่ Composition
- ออก: ระบบจะยกเลิกโครูทีนเมื่อ Composable ออกจากการจัดองค์ประกอบ
- เปิดใช้ซ้ำ: หากมีการเปลี่ยนแปลงคีย์ที่ส่งไปยัง
LaunchedEffectระบบจะยกเลิกโครูทีนที่มีอยู่และเปิดใช้โครูทีนใหม่
ตัวอย่างต่อไปนี้แสดงวิธีใช้ LaunchedEffect เพื่อสร้างภาพเคลื่อนไหวแบบกะพริบ โครูทีนจะเชื่อมโยงกับการมีอยู่ของ Composable ใน
Composition และตอบสนองต่อการเปลี่ยนแปลงการกำหนดค่า
// 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
เป็นออบเจ็กต์ State ของ Compose และจัดการวงจร
การสมัครใช้บริการให้คุณโดยอัตโนมัติ โดยค่าเริ่มต้น การเก็บรวบรวมจะเริ่มเมื่อวงจรเป็น
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()
// ...
}
คำนวณค่าแบบไม่พร้อมกันโดยใช้โฟลว์
เมื่อต้องการคำนวณค่าแบบไม่พร้อมกัน ให้ใช้ 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 ปิดอยู่
- การจัดการวงจรด้วยคอมโพเนนต์ที่รับรู้ถึงวงจร
- โหลดและแสดงข้อมูลแบบแบ่งหน้า