Skip to Content

Coroutines trong Android

1. Giới thiệu

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

2. Suspend Functions

// 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) }

3. Coroutine Builders

launch

// Fire-and-forget, không return value viewModelScope.launch { val users = repository.getUsers() _uiState.value = users }

async

// 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) }

runBlocking

// Block thread cho đến khi hoàn thành (chỉ dùng cho testing/main) fun main() = runBlocking { val result = fetchData() }

4. Dispatchers

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) } }

5. Scopes trong Android

viewModelScope

class MyViewModel : ViewModel() { fun loadData() { viewModelScope.launch { // Tự động cancel khi ViewModel cleared val data = repository.getData() } } }

lifecycleScope

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) } } } } }

6. Exception Handling

try-catch

viewModelScope.launch { try { val data = api.fetchData() _uiState.value = UiState.Success(data) } catch (e: Exception) { _uiState.value = UiState.Error(e.message) } }

CoroutineExceptionHandler

private val exceptionHandler = CoroutineExceptionHandler { _, exception -> _uiState.value = UiState.Error(exception.message) } viewModelScope.launch(exceptionHandler) { val data = api.fetchData() // Exception sẽ được handle }

supervisorScope

// Child failure không cancel parent supervisorScope { val job1 = launch { task1() } // Failure không ảnh hưởng job2 val job2 = launch { task2() } }

7. Cancellation

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 } } }

Cooperative Cancellation

suspend fun fetchAllPages() { for (page in 1..100) { ensureActive() // Check cancellation val data = api.fetchPage(page) processData(data) } }

8. withTimeout

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

9. Parallel vs Sequential

// 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()) }

10. Best Practices

// ✅ 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 }

📝 Tóm tắt

ConceptMô tả
suspendFunction có thể pause
launchFire-and-forget
asyncReturn Deferred
withContextSwitch dispatcher
viewModelScopeViewModel lifecycle
lifecycleScopeActivity/Fragment lifecycle
Dispatchers.IONetwork/disk
Dispatchers.MainUI thread
Last updated on