Bỏ qua để đến nội dung

Giới thiệu Coroutines

Coroutines là cách Kotlin xử lý lập trình bất đồng bộ (asynchronous programming). Chúng cho phép bạn viết code “trông như” đồng bộ nhưng thực sự chạy bất đồng bộ mà không block thread.

Khi app Android gọi API hoặc đọc file:

// ❌ SAI: Block UI thread -> App bị đơ (ANR)
fun loadData() {
val data = networkCall() // Mất 3 giây
updateUI(data) // User không thể tương tác trong 3 giây!
}

Android có quy tắc: UI thread (Main thread) không được làm việc nặng (network, database, file I/O).

// Callback hell - Code khó đọc, khó maintain
api.getUser(userId) { user ->
api.getPosts(user.id) { posts ->
api.getComments(posts[0].id) { comments ->
// Nested callbacks...
updateUI(user, posts, comments)
}
}
}
// ✅ Clean và dễ đọc như code đồng bộ
suspend fun loadData() {
val user = api.getUser(userId) // Đợi, nhưng không block!
val posts = api.getPosts(user.id) // Tiếp tục sau khi user có
val comments = api.getComments(posts[0].id)
updateUI(user, posts, comments)
}

Magic: Code trông như chạy lần lượt, nhưng thực ra:

  • Khi gọi getUser(), coroutine suspend (tạm dừng) và giải phóng thread
  • Thread có thể làm việc khác
  • Khi data về, coroutine resume (tiếp tục) từ đúng chỗ dừng

Coroutines Threads
Tạo mới Rất nhẹ (vài KB) Nặng (~1-2 MB)
Số lượng Hàng triệu Vài nghìn
Quản lý Tự động (structured concurrency) Manual
Cancel Dễ dàng Phức tạp
Exception Propagate tự động Dễ bị nuốt
// Coroutines: Hoạt động bình thường (~300ms)
fun main() = runBlocking {
repeat(100_000) {
launch {
delay(1000)
print(".")
}
}
}
// Threads: OutOfMemoryError!
fun main() {
repeat(100_000) {
Thread {
Thread.sleep(1000)
print(".")
}.start()
}
}

Hàm có thể tạm dừng mà không block thread:

suspend fun fetchData(): Data {
delay(1000) // Tạm dừng 1 giây (không block!)
return Data()
}

Cách khởi chạy coroutine:

// launch - Fire and forget
launch {
fetchData()
}
// async - Trả về kết quả
val deferred = async {
fetchData()
}
val result = deferred.await()

Phạm vi quản lý lifecycle của coroutines:

// ViewModel scope - tự cancel khi ViewModel bị clear
viewModelScope.launch {
// ...
}
// Lifecycle scope - tự cancel khi lifecycle destroyed
lifecycleScope.launch {
// ...
}

Thread pool nơi coroutine chạy:

// Main thread (UI)
Dispatchers.Main
// Background thread (I/O operations)
Dispatchers.IO
// CPU-intensive work
Dispatchers.Default

class UserViewModel : ViewModel() {
private val _user = MutableStateFlow<User?>(null)
val user: StateFlow<User?> = _user.asStateFlow()
fun loadUser(userId: Int) {
// Chạy trong ViewModel scope
viewModelScope.launch {
try {
// Chuyển sang IO thread để gọi network
val result = withContext(Dispatchers.IO) {
api.getUser(userId)
}
// Quay về Main thread để update UI
_user.value = result
} catch (e: Exception) {
// Xử lý lỗi
}
}
}
}

// RxJava - Học curve cao, boilerplate nhiều
api.getUser(userId)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ user ->
updateUI(user)
}, { error ->
handleError(error)
})
// Coroutines - Đơn giản hơn nhiều
viewModelScope.launch {
try {
val user = withContext(Dispatchers.IO) { api.getUser(userId) }
updateUI(user)
} catch (e: Exception) {
handleError(e)
}
}

build.gradle.kts
dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3") // Cho Android
}

Khái niệm Mô tả
Coroutine Unit of async work, nhẹ hơn thread
suspend Tạm dừng mà không block
launch Khởi chạy coroutine (fire-and-forget)
async/await Khởi chạy và lấy kết quả
Scope Quản lý lifecycle
Dispatcher Thread pool
  1. Official - Được Kotlin và Google khuyến nghị
  2. Simple - Code dễ đọc như synchronous
  3. Efficient - Nhẹ, có thể chạy hàng triệu
  4. Structured - Tự động cancel, exception handling tốt
  5. Integrate - Tích hợp tốt với Android Jetpack

Học về Suspend Functions - nền tảng của coroutines.