launch — Coroutine Builder ใน Kotlin ที่เริ่มต้น coroutine โดยไม่ส่งคืนผลลัพธ์ ส่งคืนออบเจ็กต์ Job เพื่อควบคุมการทำงาน Builder นี้ใช้รูปแบบ fire-and-forget: coroutine เริ่มทำงานในเบื้องหลังและสิ้นสุดโดยอัตโนมัติ ตามเอกสารของ JetBrains, 2024 launch เป็นวิธีหลักในการรันงานแบบขนานใน Kotlin Coroutines
ประเด็นสำคัญ
launch เป็นฟังก์ชันส่วนขยายของ Kotlin ที่สามารถใช้งานได้ผ่านการ import kotlinx.coroutines ซึ่งสร้าง coroutine ใหม่ใน CoroutineScope ที่กำหนด แตกต่างจากฟังก์ชันทั่วไป โค้ดภายใน launch จะทำงานพร้อมกัน — coroutine สามารถหยุดชั่วคราว (suspend) โดยไม่บล็อกเธรดและกลับมาทำงานต่อในภายหลัง
builder launch เป็นบล็อกพื้นฐานของโมเดล coroutine ใน Kotlin มันไม่ส่งคืนค่าที่คำนวณได้แต่ส่งคืนออบเจ็กต์ Job ที่ช่วยให้ควบคุมการทำงานของ coroutine ได้ coroutine ลูกทั้งหมดที่เริ่มต้นผ่าน launch ภายใน coroutine อื่นจะถูกผูกกับ coroutine แม่
builder launch ถูกกำหนดเป็นฟังก์ชัน inline ที่มีพารามิเตอร์หลายตัว: CoroutineScope, CoroutineContext, CoroutineStart และบล็อก suspend พารามิเตอร์มีค่าเริ่มต้น ทำให้ launch สะดวกสำหรับสถานการณ์ทั่วไป
public fun CoroutineScope.launch(
context: CoroutineContext = EmptyCoroutineContext,
start: CoroutineStart = CoroutineStart.DEFAULT,
block: suspend CoroutineScope.() -> Unit
): Job
พารามิเตอร์ context รับ CoroutineContext ที่รวม dispatcher ตัวจัดการข้อยกเว้น และองค์ประกอบที่มีชื่อ โดยส่วนใหญ่ Dispatchers.IO, Dispatchers.Main หรือ SupervisorJob ถูกส่งเพื่อแยกข้อผิดพลาด
Job — ออบเจ็กต์ที่ส่งคืนซึ่งแสดงถึงวงจรชีวิตของ coroutine Job สามารถอยู่ในสถานะ: New, Active, Completing, Completed, Cancelling, Cancelled แต่ละสถานะสะท้อนสถานะการทำงานและช่วยให้ตอบสนองต่อการเปลี่ยนแปลงได้
val job = CoroutineScope(Dispatchers.IO).launch {
repeat(10) { i ->
delay(1000L)
println("ความคืบหน้า: $i")
}
}
println("งานกำลังทำงาน: ${job.isActive}")
delay(2500L)
job.cancel()
println("งานถูกยกเลิก: ${job.isCancelled}")
Job รองรับลำดับชั้น: ถ้า coroutine แม่ถูกยกเลิก coroutine ลูกทั้งหมดจะถูกยกเลิกโดยอัตโนมัติ SupervisorJob เปลี่ยนพฤติกรรมนี้ — coroutine ลูกจะไม่ถูกยกเลิกเมื่อหนึ่งในนั้นล้มเหลว
การทำงานพร้อมกันแบบมีโครงสร้างหมายความว่า coroutine แต่ละตัวเริ่มต้นภายใน CoroutineScope ที่เฉพาะเจาะจง และ scope จะไม่เสร็จสิ้นจนกว่า coroutine ลูกทั้งหมดจะทำงานเสร็จ launch สนับสนุนหลักการนี้อย่างเต็มที่ — coroutine ที่เริ่มต้นภายใน coroutine อื่นจะเป็น coroutine ลูก
ด้วยการเรียก launch แบบซ้อน จะเกิดโครงสร้างต้นไม้ของ coroutine coroutine แม่รอให้ coroutine ลูกทั้งหมดทำงานเสร็จ ซึ่งรับประกันลำดับการทำงานที่คาดเดาได้และทำให้การจัดการทรัพยากรง่ายขึ้น
fun main() = runBlocking {
launch {
launch {
delay(1000L)
println("ลูก 1 เสร็จสิ้น")
}
launch {
delay(500L)
println("ลูก 2 เสร็จสิ้น")
}
println("ลูกทั้งหมดเสร็จสิ้นก่อนบรรทัดนี้")
}
}
พฤติกรรมนี้แตกต่างจากการทำงานพร้อมกันแบบเธรด ซึ่งเธรดลูกไม่ผูกกับเธรดแม่ ใน coroutine แม่จะไม่เสร็จสิ้น จนกว่า coroutine ลูกทั้งหมดจะทำงานเสร็จ
การจัดการข้อยกเว้นใน launch ขึ้นอยู่กับประเภทของ Job สำหรับ Job ปกติ ข้อยกเว้นจะแพร่กระจายไปยัง coroutine แม่และยกเลิกมัน สำหรับ SupervisorJob หรือ SupervisorScope ข้อยกเว้นจะถูกแยก — ข้อผิดพลาดใน coroutine ลูกหนึ่งตัวไม่ส่งผลกระทบต่อตัวอื่น
val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
scope.launch {
try {
riskyOperation()
} catch (e: Exception) {
println("จับได้: ${e.message}")
}
}
scope.launch {
println("สิ่งนี้ยังคงทำงานได้ด้วย SupervisorJob")
}
สำหรับการจัดการข้อยกเว้นที่ไม่ถูกจับในระดับโลก จะใช้ CoroutineExceptionHandler มันจับข้อยกเว้นที่ไม่ได้รับการจัดการภายใน coroutine และช่วยให้บันทึกข้อผิดพลาดโดยไม่ทำให้แอปพลิเคชันหยุดทำงาน
ใน Android launch ถูกใช้ทุกที่: จาก ViewModel ถึง WorkManager รูปแบบหลักคือการใช้ lifecycleScope ใน Fragment และ viewModelScope ใน ViewModel เพื่อยกเลิก coroutine โดยอัตโนมัติเมื่อวงจรชีวิตของคอมโพเนนต์สิ้นสุด
class ProfileViewModel : ViewModel() {
private val repository = UserRepository()
fun loadProfile(userId: String) {
viewModelScope.launch(Dispatchers.IO) {
val profile = repository.fetchProfile(userId)
withContext(Dispatchers.Main) {
_profileState.update { it.copy(profile = profile) }
}
}
}
}
viewModelScope ยกเลิก coroutine โดยอัตโนมัติเมื่อ ViewModel ถูกทำลาย ซึ่งช่วยลดการรั่วไหลและรับประกันว่าการทำงานเบื้องหลังจะไม่ดำเนินต่อหลังจากสูญเสียบริบท นอกจากนี้ สามารถใช้ withContext เพื่อสลับระหว่าง dispatcher
คำถามที่พบบ่อย
launch ส่งคืน Job และไม่ส่งคืนผลลัพธ์ ในขณะที่ async ส่งคืน Deferred<T> เพื่อรับผลลัพธ์ launch ใช้สำหรับการดำเนินการแบบ fire-and-forget async — เมื่อคุณต้องรอและใช้ค่าที่ส่งคืน
เรียก job.cancel() บนออบเจ็กต์ Job ที่บันทึกไว้ สำหรับการยกเลิกกลุ่ม ให้ยกเลิก CoroutineScope ทั้งหมดผ่าน scope.cancel() coroutine ต้องให้ความร่วมมือ — ตรวจสอบ isActive หรือใช้ฟังก์ชัน suspend ที่ยกเลิกได้
ใช้ try-catch ภายในบล็อก launch หรือส่ง CoroutineExceptionHandler ใน CoroutineContext สำหรับการแยกข้อผิดพลาด ให้ใช้ SupervisorJob — แล้วข้อยกเว้นใน coroutine ลูกหนึ่งตัวจะไม่ยกเลิกตัวอื่น
ไม่ launch เป็นฟังก์ชันส่วนขยายของ CoroutineScope หากไม่มี scope coroutine จะไม่สามารถปฏิบัติตามหลักการทำงานพร้อมกันแบบมีโครงสร้างได้ ใช้ GlobalScope.launch ด้วยความระมัดระวัง — มันสร้าง coroutine ที่ไม่ผูกกับวงจรชีวิต
จำนวนถูกจำกัดโดยพูลเธรดของ dispatcher Dispatchers.Default ใช้เธรดเท่ากับจำนวนแกน CPU Dispatchers.IO รองรับสูงสุด 64 เธรด หากเริ่มต้น coroutine มากขึ้น พวกมันจะถูกจัดคิว
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ
อ่านเพิ่มเติม