Sử dụng Kotlin Coroutines trong Android

Cấu trúc MVVM trong Android

Cấu trúc MVVM (Model-View-ViewModel) là một mô hình thiết kế phổ biến trong phát triển Android, giúp tách biệt logic xử lý và giao diện người dùng.

Thêm phụ thuộc

Để sử dụng coroutines trong dự án Android, hãy thêm các phụ thuộc sau vào file build.gradle của ứng dụng:

dependencies {
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9")
}

Thực thi trên luồng nền

Coroutines giải quyết vấn đề gì?

Trong Android, coroutines giải quyết hai vấn đề chính:

  1. Nhiệm vụ mất nhiều thời gian, làm tắc nghẽn luồng chính
  2. Đảm bảo an toàn cho luồng chính, cho phép gọi bất kỳ hàm suspend nào từ luồng chính

Một ví dụ về cách sử dụng coroutines để xử lý nhiệm vụ mất nhiều thời gian:

suspend fun getDataAndShow() {
    val result = getApi()
    show(result)
}

suspend fun getApi() = withContext(Dispatchers.IO) { /*...*/ }

Đảm bảo an toàn cho luồng chính

Để đảm bảo an toàn cho luồng chính, bạn có thể sử dụng Dispatchers.Default hoặc Dispatchers.IO. Các thư viện như Room, Retrofit, và Volley thường tự quản lý luồng, vì vậy bạn không cần phải lo lắng về việc chuyển đổi luồng.

Hiệu suất của withContext

withContext cho phép bạn kiểm soát luồng mà mã của bạn chạy, tránh việc sử dụng callback. Điều này giúp cải thiện hiệu suất và tính dễ đọc của mã.

Concurrent cấu trúc

Theo dõi coroutines

Việc theo dõi hàng nghìn coroutines bằng tay rất khó khăn. Kotlin cung cấp structured concurrency để giúp theo dõi và hủy bỏ coroutines một cách hiệu quả.

Hủy bỏ tác vụ thông qua scope

Coroutines phải chạy trong CoroutineScope. CoroutineScope theo dõi tất cả các coroutines và có thể hủy bỏ chúng. Điều này rất hữu ích trong phát triển Android, vì nó giúp dọn dẹp các tác vụ khi người dùng rời khỏi màn hình.

fun foo(scope: CoroutineScope) {
    scope.launch {
        test()  // Cho phép
    }

    val task = scope.async { }
    task.await() // Không cho phép
    
    test() // Không cho phép
}

Khởi tạo coroutines trong ViewModel

Trong Android, coroutines thường được khởi tạo trong ViewModel. Điều này giúp đảm bảo rằng các tác vụ sẽ được hủy bỏ khi người dùng rời khỏi màn hình.

class LatestNewsViewModel(
    private val getLatestNewsWithAuthors: GetLatestNewsWithAuthorsUseCase
) : ViewModel() {

    private val _uiState = MutableStateFlow<LatestNewsUiState>(LatestNewsUiState.Loading)
    val uiState: StateFlow<LatestNewsUiState> = _uiState

    fun loadNews() {
        viewModelScope.launch {
            val latestNewsWithAuthors = getLatestNewsWithAuthors()
            _uiState.value = LatestNewsUiState.Success(latestNewsWithAuthors)
        }
    }
}

Một số thực hành tốt khi sử dụng coroutines trong Android

Chèn dispatchers

Không nên hardcode Dispatchers, thay vào đó, hãy chèn chúng như sau:

class NewsRepository(
    private val defaultDispatcher: CoroutineDispatcher = Dispatchers.Default
) {
    suspend fun loadNews() = withContext(defaultDispatcher) { /* ... */ }
}

Hàm suspend nên đảm bảo an toàn cho luồng

Hàm suspend nên đảm bảo an toàn cho mọi luồng, không nên để người gọi phải chuyển đổi luồng.

ViewModel nên tạo coroutines

ViewModel nên tạo coroutines thay vì công khai hàm suspend để thực hiện logic kinh doanh.

Không công khai các kiểu có thể thay đổi

Nên công khai các kiểu không thể thay đổi để tập trung các thay đổi trong một lớp, giúp dễ dàng debug hơn.

Tầng dữ liệu và kinh doanh nên công khai hàm suspend và data flow

Tầng dữ liệu và kinh doanh nên công khai hàm suspend cho các cuộc gọi một lần và data flow để nhận thông báo về sự thay đổi dữ liệu.

Chèn TestCoroutineDispatcher trong thử nghiệm

Nên chèn TestCoroutineDispatcher trong các lớp thử nghiệm để tăng tính xác định và tránh điều kiện cạnh tranh.

Tránh sử dụng GlobalScope

Tránh sử dụng GlobalScope vì nó làm tăng độ cứng của mã và gây khó khăn trong việc thử nghiệm.

Đặt coroutines có thể hủy bỏ

Coroutines nên được đặt là có thể hủy bỏ để đảm bảo rằng các tác vụ có thể được dọn dẹp khi cần thiết.

Chú ý đến ngoại lệ

Việc xử lý ngoại lệ không đúng cách trong coroutines có thể dẫn đến sự cố của ứng dụng. Hãy chắc chắn bắt và xử lý ngoại lệ trong coroutines.

Thẻ: Kotlin Coroutines Android mvvm ViewModel

Đăng vào ngày 25 tháng 5 lúc 16:30