# Kotlin Coroutines cho Android: Huong dan day du 2026 > Huong dan toan dien ve Kotlin coroutines trong phat trien Android: suspend functions, scopes, dispatchers va cac pattern nang cao. - Published: 2026-01-04 - Updated: 2026-04-02 - Author: Anthony Fillion-Maillet - Tags: kotlin, coroutines, android, async, concurrency - Reading time: 12 min --- Kotlin coroutines da thay doi hoan toan cach lap trinh bat dong bo tren Android. Thoi dai cua callback hell va AsyncTask loi thoi da qua: voi coroutines, ma bat dong bo duoc viet giong nhu ma dong bo, dong thoi van dam bao hieu suat va kha nang bao tri. > **Tai sao chon coroutines?** > > Coroutines co trong luong nhe (hang ngan coroutine co the chay tren mot thread duy nhat), ho tro huy tu dong, va tich hop lien mach voi Jetpack cung he sinh thai Android hien dai. ## Hieu ro cac khai niem co ban Truoc khi bat dau viet code, can nam vung nhung diem lam cho coroutines tro nen manh me. ### Coroutine la gi? Coroutine la mot the hien cua phep tinh co kha nang tam dung. Khac voi thread, coroutine khong chan (block): chung tam dung thuc thi va giai phong thread cho cac tac vu khac. ```kotlin // BasicCoroutine.kt import kotlinx.coroutines.* fun main() = runBlocking { launch { delay(1000L) // Suspend without blocking println("World!") } println("Hello,") } // Output: Hello, World! ``` ### Suspend Functions: Trai tim cua Coroutines Tu khoa `suspend` chi ra rang mot ham co the tam dung viec thuc thi coroutine ma khong chan thread. ```kotlin // SuspendFunction.kt suspend fun fetchUserData(userId: String): User { return withContext(Dispatchers.IO) { // Network call - runs on an IO thread apiService.getUser(userId) } } suspend fun fetchUserWithPosts(userId: String): UserWithPosts { // Sequential execution val user = fetchUserData(userId) val posts = fetchUserPosts(userId) return UserWithPosts(user, posts) } ``` > **Quy tac vang**: Mot suspend function chi co the duoc goi tu mot suspend function khac hoac tu ben trong mot coroutine. ## Coroutine Scopes: Quan ly vong doi Scope xac dinh vong doi cua coroutines. Day la yeu to then chot de tranh ro ri bo nho. ### viewModelScope: Scope danh cho ViewModel ```kotlin // UserViewModel.kt class UserViewModel( private val userRepository: UserRepository ) : ViewModel() { private val _uiState = MutableStateFlow(UserUiState.Loading) val uiState: StateFlow = _uiState.asStateFlow() fun loadUser(userId: String) { viewModelScope.launch { _uiState.value = UserUiState.Loading try { val user = userRepository.getUser(userId) _uiState.value = UserUiState.Success(user) } catch (e: Exception) { _uiState.value = UserUiState.Error(e.message) } } } } sealed class UserUiState { object Loading : UserUiState() data class Success(val user: User) : UserUiState() data class Error(val message: String?) : UserUiState() } ``` ### lifecycleScope: Danh cho Activity va Fragment ```kotlin // UserFragment.kt class UserFragment : Fragment() { private val viewModel: UserViewModel by viewModels() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) viewLifecycleOwner.lifecycleScope.launch { viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) { viewModel.uiState.collect { state -> when (state) { is UserUiState.Loading -> showLoading() is UserUiState.Success -> showUser(state.user) is UserUiState.Error -> showError(state.message) } } } } } } ``` > **Canh bao ve ro ri bo nho** > > Khong bao gio su dung `GlobalScope` trong ung dung Android. Cac coroutine khoi chay bang `GlobalScope` khong gan voi bat ky vong doi nao va co the gay ro ri bo nho. ## Dispatchers: Kiem soat luong thuc thi Dispatchers xac dinh coroutine se chay tren thread nao. ### 4 Dispatcher chinh ```kotlin // Dispatchers.kt // Main: main thread (UI) viewModelScope.launch(Dispatchers.Main) { textView.text = "UI update" } // IO: I/O operations (network, database) viewModelScope.launch(Dispatchers.IO) { val data = repository.fetchFromNetwork() } // Default: CPU-intensive computations viewModelScope.launch(Dispatchers.Default) { val result = heavyComputation(data) } // Unconfined: inherits caller context (rare use) ``` ### withContext: Chuyen doi Dispatcher ```kotlin // ImageProcessor.kt class ImageProcessor { suspend fun processImage(bitmap: Bitmap): Bitmap { return withContext(Dispatchers.Default) { // CPU-intensive processing on Default applyFilters(bitmap) } } suspend fun saveToGallery(bitmap: Bitmap) { withContext(Dispatchers.IO) { // Disk write on IO saveToFile(bitmap) } } } // Usage in ViewModel viewModelScope.launch { val processed = imageProcessor.processImage(originalBitmap) imageProcessor.saveToGallery(processed) // Automatic return to Main for UI update _uiState.value = UiState.Success(processed) } ``` ## Thuc thi song song voi async/await De thuc thi nhieu tac vu dong thoi va ket hop ket qua, su dung `async`. ```kotlin // ParallelExecution.kt suspend fun loadDashboard(): Dashboard { return coroutineScope { // Parallel launch val userDeferred = async { userRepository.getUser() } val statsDeferred = async { statsRepository.getStats() } val notificationsDeferred = async { notificationRepository.getNotifications() } // Await results Dashboard( user = userDeferred.await(), stats = statsDeferred.await(), notifications = notificationsDeferred.await() ) } } ``` > **Hieu suat** > > Voi `async`, ca 3 loi goi duoc thuc thi song song. Neu moi loi goi mat 1 giay, tong thoi gian chi khoang 1 giay thay vi 3 giay khi thuc thi tuan tu. ## Xu ly loi trong Coroutines ### try/catch truyen thong ```kotlin // ErrorHandling.kt viewModelScope.launch { try { val user = userRepository.getUser(userId) _uiState.value = UiState.Success(user) } catch (e: HttpException) { _uiState.value = UiState.Error("Server error: ${e.code()}") } catch (e: IOException) { _uiState.value = UiState.Error("Network error") } catch (e: Exception) { _uiState.value = UiState.Error("Unexpected error") } } ``` ### CoroutineExceptionHandler ```kotlin // ExceptionHandler.kt class UserViewModel : ViewModel() { private val exceptionHandler = CoroutineExceptionHandler { _, throwable -> _uiState.value = UiState.Error(throwable.message) Timber.e(throwable, "Error in coroutine") } fun loadUser(userId: String) { viewModelScope.launch(exceptionHandler) { val user = userRepository.getUser(userId) _uiState.value = UiState.Success(user) } } } ``` ### Result Wrapper Pattern ```kotlin // ResultPattern.kt sealed class Result { data class Success(val data: T) : Result() data class Error(val exception: Throwable) : Result() } suspend fun safeApiCall(apiCall: suspend () -> T): Result { return try { Result.Success(apiCall()) } catch (e: Exception) { Result.Error(e) } } // Usage class UserRepository(private val api: UserApi) { suspend fun getUser(id: String): Result = safeApiCall { api.getUser(id) } } // In ViewModel viewModelScope.launch { when (val result = userRepository.getUser(userId)) { is Result.Success -> _uiState.value = UiState.Success(result.data) is Result.Error -> _uiState.value = UiState.Error(result.exception.message) } } ``` ## Huy coroutine: Don dep tai nguyen dung cach Coroutines ho tro co che huy hop tac (cooperative cancellation). Day la dieu can thiet de tranh ro ri tai nguyen. ### Tu dong huy voi Scopes ```kotlin // SearchViewModel.kt class SearchViewModel : ViewModel() { private var searchJob: Job? = null fun search(query: String) { // Cancel previous search searchJob?.cancel() searchJob = viewModelScope.launch { delay(300) // Debounce val results = searchRepository.search(query) _searchResults.value = results } } } ``` ### Kiem tra trang thai huy ```kotlin // CancellationCheck.kt suspend fun processLargeList(items: List) { items.forEach { item -> // Check if coroutine is cancelled ensureActive() processItem(item) } } suspend fun downloadFiles(urls: List) = coroutineScope { urls.map { url -> async { try { downloadFile(url) } catch (e: CancellationException) { cleanupPartialDownload(url) throw e // Re-throw to propagate cancellation } } }.awaitAll() } ``` > **Khong bao gio nuot CancellationException**: neu bat `Exception`, can nem lai `CancellationException` de viec huy duoc lan truyen dung cach. ## Flow: Lap trinh phan ung Flow la tuong duong cua RxJava Observable trong the gioi coroutines, nhung don gian hon va tich hop san. ### Tao va thu thap Flow ```kotlin // FlowBasics.kt fun getUsers(): Flow> = flow { while (true) { val users = userApi.getUsers() emit(users) delay(5000) // Poll every 5 seconds } } // Flow from Room @Dao interface UserDao { @Query("SELECT * FROM users") fun getAllUsers(): Flow> } // Collecting in ViewModel viewModelScope.launch { userDao.getAllUsers() .catch { e -> _uiState.value = UiState.Error(e.message) } .collect { users -> _uiState.value = UiState.Success(users) } } ``` ### StateFlow va SharedFlow ```kotlin // StateFlowVsSharedFlow.kt class EventViewModel : ViewModel() { // StateFlow: keeps last value, ideal for UI state private val _uiState = MutableStateFlow(UiState.Initial) val uiState: StateFlow = _uiState.asStateFlow() // SharedFlow: for one-shot events (navigation, snackbar) private val _events = MutableSharedFlow() val events: SharedFlow = _events.asSharedFlow() fun onButtonClick() { viewModelScope.launch { _events.emit(UiEvent.NavigateToDetail) } } } sealed class UiEvent { object NavigateToDetail : UiEvent() data class ShowSnackbar(val message: String) : UiEvent() } ``` ### Cac toan tu Flow thiet yeu ```kotlin // FlowOperators.kt userRepository.getUsers() .map { users -> users.filter { it.isActive } } .distinctUntilChanged() .debounce(300) .flatMapLatest { users -> fetchUserDetails(users) } .catch { e -> emit(emptyList()) } .onEach { users -> analytics.logUserCount(users.size) } .stateIn( scope = viewModelScope, started = SharingStarted.WhileSubscribed(5000), initialValue = emptyList() ) ``` ## Cac pattern nang cao ### Retry voi Exponential Backoff ```kotlin // RetryPattern.kt suspend fun retryWithBackoff( times: Int = 3, initialDelay: Long = 100, maxDelay: Long = 1000, factor: Double = 2.0, block: suspend () -> T ): T { var currentDelay = initialDelay repeat(times - 1) { attempt -> try { return block() } catch (e: Exception) { Timber.w("Attempt ${attempt + 1} failed, retrying in ${currentDelay}ms") } delay(currentDelay) currentDelay = (currentDelay * factor).toLong().coerceAtMost(maxDelay) } return block() } // Usage val user = retryWithBackoff { userApi.getUser(userId) } ``` ### Timeout ```kotlin // TimeoutPattern.kt suspend fun fetchWithTimeout() { try { val result = withTimeout(5000L) { api.fetchData() } processResult(result) } catch (e: TimeoutCancellationException) { showError("Request took too long") } } // Or with a default value val result = withTimeoutOrNull(5000L) { api.fetchData() } ?: defaultValue ``` ## Ket luan Kotlin coroutines da tro thanh cong cu khong the thieu trong phat trien Android hien dai. Chung mang den cach tiep can bat dong bo thanh lich va hieu qua, tich hop hoan hao voi he sinh thai Jetpack. ### Danh sach kiem tra - Su dung `viewModelScope` va `lifecycleScope` de tranh ro ri bo nho - Chon dung Dispatcher (Main, IO, Default) - Xu ly loi bang try/catch hoac Result wrapper - Trien khai co che huy hop tac - Su dung Flow cho cac luong du lieu phan ung - Uu tien StateFlow cho trang thai UI, SharedFlow cho su kien Viec lam chu coroutines se mang lai loi the dang ke trong cac du an Android va phong van ky thuat. Hay thuc hanh thuong xuyen va kham pha cac pattern nang cao. --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/vi/blog/android/mastering-kotlin-coroutines