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

Coroutines trong Android

Kotlin Coroutines giúp viết async code như synchronous code, tránh callback hell.

// Suspend function có thể pause và resume
suspend fun fetchUser(id: Int): User {
delay(1000) // Non-blocking delay
return api.getUser(id)
}
// Chỉ gọi được từ coroutine hoặc suspend function khác
viewModelScope.launch {
val user = fetchUser(123)
updateUI(user)
}
// Fire-and-forget, không return value
viewModelScope.launch {
val users = repository.getUsers()
_uiState.value = users
}
// Return Deferred, await để lấy kết quả
viewModelScope.launch {
val deferredUser = async { api.getUser(1) }
val deferredPosts = async { api.getPosts(1) }
// Parallel execution
val user = deferredUser.await()
val posts = deferredPosts.await()
_uiState.value = UserWithPosts(user, posts)
}
// Block thread cho đến khi hoàn thành (chỉ dùng cho testing/main)
fun main() = runBlocking {
val result = fetchData()
}
viewModelScope.launch {
// Default: CPU-intensive work
val computed = withContext(Dispatchers.Default) {
heavyComputation()
}
// IO: Network, disk operations
val data = withContext(Dispatchers.IO) {
api.fetchData()
}
// Main: UI updates
withContext(Dispatchers.Main) {
updateUI(data)
}
}
class MyViewModel : ViewModel() {
fun loadData() {
viewModelScope.launch {
// Tự động cancel khi ViewModel cleared
val data = repository.getData()
}
}
}
class MyActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
lifecycleScope.launch {
// Tự động cancel khi Activity destroyed
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.uiState.collect { state ->
updateUI(state)
}
}
}
}
}
viewModelScope.launch {
try {
val data = api.fetchData()
_uiState.value = UiState.Success(data)
} catch (e: Exception) {
_uiState.value = UiState.Error(e.message)
}
}
private val exceptionHandler = CoroutineExceptionHandler { _, exception ->
_uiState.value = UiState.Error(exception.message)
}
viewModelScope.launch(exceptionHandler) {
val data = api.fetchData() // Exception sẽ được handle
}
// Child failure không cancel parent
supervisorScope {
val job1 = launch { task1() } // Failure không ảnh hưởng job2
val job2 = launch { task2() }
}
class MyViewModel : ViewModel() {
private var fetchJob: Job? = null
fun search(query: String) {
fetchJob?.cancel() // Cancel previous search
fetchJob = viewModelScope.launch {
delay(300) // Debounce
val results = api.search(query)
_results.value = results
}
}
}
suspend fun fetchAllPages() {
for (page in 1..100) {
ensureActive() // Check cancellation
val data = api.fetchPage(page)
processData(data)
}
}
viewModelScope.launch {
try {
val result = withTimeout(5000) {
api.slowRequest()
}
} catch (e: TimeoutCancellationException) {
showError("Request timed out")
}
}
// Or with null instead of exception
val result = withTimeoutOrNull(5000) {
api.slowRequest()
} ?: defaultValue
// Sequential: 2 giây
suspend fun sequential() {
val user = api.getUser(1) // 1 giây
val posts = api.getPosts(1) // 1 giây
}
// Parallel: 1 giây
suspend fun parallel() = coroutineScope {
val user = async { api.getUser(1) }
val posts = async { api.getPosts(1) }
UserWithPosts(user.await(), posts.await())
}
// ✅ Good: Inject dispatcher
class UserRepository(
private val api: ApiService,
private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO
) {
suspend fun getUsers() = withContext(ioDispatcher) {
api.getUsers()
}
}
// ✅ Good: Use viewModelScope
class MyViewModel : ViewModel() {
fun loadData() {
viewModelScope.launch { ... }
}
}
// ❌ Bad: GlobalScope
GlobalScope.launch {
// Không được quản lý lifecycle
}
// ❌ Bad: Blocking main thread
runBlocking {
// Đừng dùng trong production code
}

Concept Mô tả
suspend Function có thể pause
launch Fire-and-forget
async Return Deferred
withContext Switch dispatcher
viewModelScope ViewModel lifecycle
lifecycleScope Activity/Fragment lifecycle
Dispatchers.IO Network/disk
Dispatchers.Main UI thread