Coroutine Builder — ฟังก์ชันของ Kotlin Coroutines ที่สร้างและเริ่มทำงานโครูทีน โดยกำหนดวิธีดำเนินการ ตัวสร้าง launch, async, runBlocking และ produce ครอบคลุมสถานการณ์ต่างๆ ตั้งแต่งานพื้นหลังไปจนถึงการคำนวณแบบขนานพร้อมส่งคืนผลลัพธ์ ตามข้อมูลจาก JetBrains, 2024, Coroutine Builder เป็นรากฐานของโมเดลโครูทีน ให้การทำงานพร้อมกันแบบมีโครงสร้างและการจัดการวงจรชีวิต
ประเด็นสำคัญ
Coroutine Builder เป็นฟังก์ชันส่วนขยายของ Kotlin ที่รับ CoroutineScope และบล็อก suspend สร้างและเริ่มโครูทีนใหม่ ตัวสร้างแต่ละตัวกำหนดว่าโครูทีนจะดำเนินการอย่างไร: มีหรือไม่มีการส่งคืนผลลัพธ์ มีการบล็อกเธรดหรือแบบอะซิงโครนัส ตัวสร้างเป็นจุดเริ่มต้นของโมเดลโครูทีนของภาษา
ตัวสร้างทั้งหมดทำงานผ่าน CoroutineScope ซึ่งจัดการวงจรชีวิตของโครูทีนย่อย เมื่อขอบเขตถูกยกเลิก โครูทีนทั้งหมดที่เริ่มผ่านขอบเขตนั้นจะถูกยกเลิกโดยอัตโนมัติ — นี่คือหลักการของ การทำงานพร้อมกันแบบมีโครงสร้าง วิธีการนี้ป้องกันการรั่วไหลของโครูทีนและรับประกันการสิ้นสุดที่คาดเดาได้
import kotlinx.coroutines.*
fun main() = runBlocking {
// ตัวสร้างทำงานภายใน CoroutineScope
val job = launch {
delay(1000L)
println("โลก!")
}
println("สวัสดี,")
job.join()
}
Kotlin มีตัวสร้างโครูทีนในตัวสี่ประเภท: launch, async, runBlocking และ produce แต่ละประเภทมีชนิดส่งคืนและขอบเขตการใช้งานของตนเอง สำหรับการพัฒนาแอปพลิเคชันมือถือ Android ตัวสร้างหลักคือ launch และ async — ทำงานแบบไม่บล็อกและสามารถทำงานร่วมกับคอมโพเนนต์ทางสถาปัตยกรรมได้
| ตัวสร้าง | ชนิดส่งคืน | การบล็อกเธรด | สถานการณ์ |
|---|---|---|---|
| launch | Job | ไม่ | งาน fire-and-forget |
| async | Deferred<T> | ไม่ | การคำนวณแบบขนาน |
| runBlocking | T | ใช่ | การทดสอบ, ฟังก์ชัน main |
| produce | ReceiveChannel<E> | ไม่ | สตรีมมิ่ง (เลิกใช้) |
ตัวสร้างแต่ละตัวรับพารามิเตอร์เพิ่มเติม: CoroutineStart (กลยุทธ์การเริ่ม), CoroutineContext (ตัวจัดส่ง, ข้อยกเว้น) และบล็อกโค้ดที่มีชื่อ โดยค่าเริ่มต้น โครูทีนจะเริ่มทันที (CoroutineStart.DEFAULT)
launch เป็นตัวสร้างที่ใช้มากที่สุดในการพัฒนา Android มันเริ่มโครูทีนที่ไม่ส่งคืนผลลัพธ์ และส่งคืนออบเจกต์ Job สำหรับจัดการวงจรชีวิต นี่เป็นตัวเลือกที่เหมาะสำหรับการดำเนินการที่ต้องการเพียงเอฟเฟกต์ข้างเคียง: บันทึกลงฐานข้อมูล ส่งการวิเคราะห์ อัปเดต UI
ตัวสร้าง launch รับ CoroutineScope, CoroutineContext ที่ไม่บังคับ และบล็อก suspend Job ที่ส่งคืนช่วยให้ยกเลิกโครูทีน รอให้เสร็จสมบูรณ์ หรือตรวจสอบสถานะได้
val scope = CoroutineScope(Dispatchers.IO + SupervisorJob())
val job: Job = scope.launch(CoroutineStart.LAZY) {
val data = fetchFromNetwork()
saveToDatabase(data)
}
job.start()
job.join()
พารามิเตอร์ CoroutineStart.LAZY เลื่อนการดำเนินการจนกว่าจะเรียก start() หรือ join() อย่างชัดเจน ซึ่งมีประโยชน์สำหรับการเริ่มต้นแบบขี้เกียจและการดำเนินการแบบมีเงื่อนไข สำหรับการดำเนินการทันทีมาตรฐาน ใช้ CoroutineStart.DEFAULT หรือละพารามิเตอร์
async เป็นตัวสร้างที่ส่งคืน Deferred<T> — สัญญาแบบอะซิงโครนัสของผลลัพธ์ การเรียก await() จะระงับโครูทีนจนกว่าจะได้รับผลลัพธ์ โดยไม่บล็อกเธรด นี่เป็นกลไกหลักสำหรับงานแบบขนานในโครูทีน Kotlin
async มีประสิทธิภาพโดยเฉพาะเมื่อคุณต้องดำเนินการหลายอย่างที่เป็นอิสระพร้อมกัน ต่างจากการเรียกฟังก์ชัน suspend แบบเรียงลำดับ async จะเริ่มโครูทีนแบบขนาน ลด เวลาในการดำเนินการทั้งหมด
suspend fun fetchUserData(): UserData {
val deferred1 = CoroutineScope(Dispatchers.IO).async { api.getProfile() }
val deferred2 = CoroutineScope(Dispatchers.IO).async { api.getSettings() }
val deferred3 = CoroutineScope(Dispatchers.IO).async { api.getNotifications() }
return UserData(
profile = deferred1.await(),
settings = deferred2.await(),
notifications = deferred3.await()
)
}
Deferred สืบทอดจาก Job ดังนั้น async จึงรองรับการดำเนินการวงจรชีวิตทั้งหมด: การยกเลิก การรอให้เสร็จสมบูรณ์ การจัดการข้อยกเว้น เมื่อขอบเขตถูกยกเลิก โครูทีน Deferred ย่อยจะถูกยกเลิกโดยอัตโนมัติ
runBlocking เป็นตัวสร้างเดียวที่บล็อกเธรดปัจจุบันจนกว่าโครูทีนจะเสร็จสมบูรณ์ มันสร้าง CoroutineScope ใหม่และเริ่มโครูทีนที่ส่งเข้าไป บล็อกเธรดที่เรียก ใช้ในจุดเริ่มต้น main(), ในการทดสอบ และเมื่อทำงานร่วมกับโค้ดแบบบล็อก
runBlocking เหมาะสมในสามสถานการณ์: จุดเริ่มต้นของแอปพลิเคชัน (main), การทดสอบหน่วยของฟังก์ชัน suspend และการทำงานร่วมกับไลบรารีที่ใช้ callback ซึ่งไม่สามารถใช้ suspend ได้ ในโค้ด Android ที่ใช้งานจริง การใช้ runBlocking บนเธรดหลัก ไม่แนะนำอย่างยิ่ง
class CoroutineTest {
@Test
fun `test suspend function`() = runBlocking {
val result = mySuspendFunction()
assertEquals("expected", result)
}
}
สำหรับการทดสอบ แนะนำให้ใช้ kotlinx-coroutines-test กับ TestCoroutineDispatcher แทน runBlocking — ซึ่งให้การควบคุมเวลาและหลีกเลี่ยงการบล็อกในสภาพแวดล้อมการทดสอบ
การเลือก Coroutine Builder ขึ้นอยู่กับผลลัพธ์ที่ส่งคืนและสถานการณ์การดำเนินการ หากการดำเนินการไม่ต้องการส่งคืนข้อมูล — ใช้ launch หากคุณต้องการผลลัพธ์ของการดำเนินการแบบอะซิงโครนัส — ใช้ async ใช้ runBlocking เฉพาะเป็นสะพาน และแทนที่ produce ด้วย Flow สำหรับสตรีมแบบรีแอกทีฟ
ในโปรเจกต์ Android ที่ใช้ Kotlin Coroutines คู่ตัวสร้างหลักคือ launch และ async ใช้ launch ใน ViewModel และ UseCases เพื่อเริ่มโครูทีน ในขณะที่ async ใช้สำหรับคำขอแบบขนานไปยังเครือข่ายหรือฐานข้อมูล ไลบรารีสมัยใหม่ (Ktor, Room) รองรับฟังก์ชัน suspend อยู่แล้ว ซึ่ง ลดความจำเป็น ในการใช้ async โดยตรง
คำถามที่พบบ่อย
launch ส่งคืน Job และไม่ส่งคืนผลลัพธ์การดำเนินการ ในขณะที่ async ส่งคืน Deferred<T> — ออบเจกต์ที่สามารถรับผลลัพธ์ได้ผ่าน await() ใช้ launch สำหรับการดำเนินการแบบ fire-and-forget และ async สำหรับงานที่ส่งคืนข้อมูล
ไม่แนะนำ runBlocking บนเธรดหลักทำให้เกิด ANR และบล็อก UI ให้ใช้ lifecycleScope.launch ภายใน Activity และ Fragment — เป็นโซลูชันในตัวที่ไม่มีการบล็อก
ตัวสร้าง launch ส่งคืนออบเจกต์ Job ซึ่งช่วยให้ควบคุมวงจรชีวิตของโครูทีนได้: ยกเลิก (cancel), รอให้เสร็จ (join), ตรวจสอบสถานะ (isActive, isCompleted, isCancelled)
Deferred<T> คือสัญญาแบบอะซิงโครนัสของผลลัพธ์ ซึ่งส่งคืนโดยตัวสร้าง async มันสืบทอดจาก Job และเพิ่มเมธอด: await() สำหรับรับผลลัพธ์, getCompleted() สำหรับการเข้าถึงแบบไม่บล็อก, และ getCompletionExceptionOrNull() สำหรับตรวจสอบข้อยกเว้น
ใช้พารามิเตอร์ CoroutineStart.LAZY: scope.launch(start = CoroutineStart.LAZY) { ... } จากนั้นเรียก job.start() หรือ job.join() เพื่อดำเนินการจริง ซึ่งมีประโยชน์สำหรับการเริ่มต้นแบบขี้เกียจและการดำเนินการโครูทีนแบบมีเงื่อนไข
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ
อ่านเพิ่มเติม