Coroutines trong Android
1. Giới thiệu
Phần tiêu đề “1. Giới thiệu”Kotlin Coroutines giúp viết async code như synchronous code, tránh callback hell.
2. Suspend Functions
Phần tiêu đề “2. Suspend Functions”// Suspend function có thể pause và resumesuspend 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ácviewModelScope.launch { val user = fetchUser(123) updateUI(user)}3. Coroutine Builders
Phần tiêu đề “3. Coroutine Builders”launch
Phần tiêu đề “launch”// Fire-and-forget, không return valueviewModelScope.launch { val users = repository.getUsers() _uiState.value = users}async
Phần tiêu đề “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
Phần tiêu đề “runBlocking”// Block thread cho đến khi hoàn thành (chỉ dùng cho testing/main)fun main() = runBlocking { val result = fetchData()}4. Dispatchers
Phần tiêu đề “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
Phần tiêu đề “5. Scopes trong Android”viewModelScope
Phần tiêu đề “viewModelScope”class MyViewModel : ViewModel() { fun loadData() { viewModelScope.launch { // Tự động cancel khi ViewModel cleared val data = repository.getData() } }}lifecycleScope
Phần tiêu đề “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
Phần tiêu đề “6. Exception Handling”try-catch
Phần tiêu đề “try-catch”viewModelScope.launch { try { val data = api.fetchData() _uiState.value = UiState.Success(data) } catch (e: Exception) { _uiState.value = UiState.Error(e.message) }}CoroutineExceptionHandler
Phần tiêu đề “CoroutineExceptionHandler”private val exceptionHandler = CoroutineExceptionHandler { _, exception -> _uiState.value = UiState.Error(exception.message)}
viewModelScope.launch(exceptionHandler) { val data = api.fetchData() // Exception sẽ được handle}supervisorScope
Phần tiêu đề “supervisorScope”// Child failure không cancel parentsupervisorScope { val job1 = launch { task1() } // Failure không ảnh hưởng job2 val job2 = launch { task2() }}7. Cancellation
Phần tiêu đề “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
Phần tiêu đề “Cooperative Cancellation”suspend fun fetchAllPages() { for (page in 1..100) { ensureActive() // Check cancellation val data = api.fetchPage(page) processData(data) }}8. withTimeout
Phần tiêu đề “8. withTimeout”viewModelScope.launch { try { val result = withTimeout(5000) { api.slowRequest() } } catch (e: TimeoutCancellationException) { showError("Request timed out") }}
// Or with null instead of exceptionval result = withTimeoutOrNull(5000) { api.slowRequest()} ?: defaultValue9. Parallel vs Sequential
Phần tiêu đề “9. Parallel vs Sequential”// Sequential: 2 giâysuspend fun sequential() { val user = api.getUser(1) // 1 giây val posts = api.getPosts(1) // 1 giây}
// Parallel: 1 giâysuspend fun parallel() = coroutineScope { val user = async { api.getUser(1) } val posts = async { api.getPosts(1) }
UserWithPosts(user.await(), posts.await())}10. Best Practices
Phần tiêu đề “10. Best Practices”// ✅ Good: Inject dispatcherclass UserRepository( private val api: ApiService, private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO) { suspend fun getUsers() = withContext(ioDispatcher) { api.getUsers() }}
// ✅ Good: Use viewModelScopeclass MyViewModel : ViewModel() { fun loadData() { viewModelScope.launch { ... } }}
// ❌ Bad: GlobalScopeGlobalScope.launch { // Không được quản lý lifecycle}
// ❌ Bad: Blocking main threadrunBlocking { // Đừng dùng trong production code}📝 Tóm tắt
Phần tiêu đề “📝 Tóm tắt”| 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 |