DEV Community

myougaTheAxo
myougaTheAxo

Posted on

Kotlin Coroutines & Flow — Complete Async Guide for Android

Kotlin Coroutines simplify asynchronous programming on Android. Learn how to manage background work, parallel execution, and reactive data streams.

ViewModelScope & Dispatchers

Launch coroutines safely in your ViewModel:

class MyViewModel : ViewModel() {
    fun loadData() {
        viewModelScope.launch {
            // Runs on Main dispatcher
            val data = fetchData()
            updateUI(data)
        }
    }

    private suspend fun fetchData(): String {
        return withContext(Dispatchers.IO) {
            // Network/database work on IO thread
            networkService.getData()
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Dispatchers

Choose the right dispatcher for your task:

// Main - UI updates
viewModelScope.launch(Dispatchers.Main) {
    uiState.value = newState
}

// IO - Network, database, file I/O
viewModelScope.launch(Dispatchers.IO) {
    val result = database.query()
}

// Default - Heavy computation
viewModelScope.launch(Dispatchers.Default) {
    val result = computeHeavyData()
}
Enter fullscreen mode Exit fullscreen mode

Async/Await Parallel Execution

Run multiple coroutines in parallel:

viewModelScope.launch {
    val userDeferred = async(Dispatchers.IO) { fetchUser() }
    val postsDeferred = async(Dispatchers.IO) { fetchPosts() }

    val user = userDeferred.await()
    val posts = postsDeferred.await()
    updateUI(user, posts)
}
Enter fullscreen mode Exit fullscreen mode

Flow Basics

Emit multiple values over time:

fun getTemperatureUpdates(): Flow<Int> = flow {
    while (currentCoroutineContext().isActive) {
        val temperature = readTemperature()
        emit(temperature)
        delay(1000)
    }
}

// Collect in UI
viewModelScope.launch {
    getTemperatureUpdates().collect { temp ->
        temperatureState.value = temp
    }
}
Enter fullscreen mode Exit fullscreen mode

StateFlow vs SharedFlow

Manage state and events:

// StateFlow - holds single state value
private val _uiState = MutableStateFlow(UiState.Loading)
val uiState: StateFlow<UiState> = _uiState.asStateFlow()

// SharedFlow - broadcasts events to multiple subscribers
private val _events = MutableSharedFlow<Event>()
val events: SharedFlow<Event> = _events.asSharedFlow()

suspend fun emitEvent(event: Event) {
    _events.emit(event)
}
Enter fullscreen mode Exit fullscreen mode

Flow Operators

Transform and filter data streams:

viewModelScope.launch {
    searchQuery
        .debounce(300.ms)
        .distinctUntilChanged()
        .flatMapLatest { query ->
            searchDatabase(query)
        }
        .catch { error ->
            _error.value = error.message
        }
        .stateIn(
            scope = viewModelScope,
            started = SharingStarted.WhileSubscribed(5000),
            initialValue = emptyList()
        )
        .collect { results ->
            _searchResults.value = results
        }
}
Enter fullscreen mode Exit fullscreen mode

Compose Integration

Use Flow with Compose:

@Composable
fun MyScreen(viewModel: MyViewModel = viewModel()) {
    val uiState by viewModel.uiState.collectAsStateWithLifecycle()

    when (uiState) {
        is UiState.Loading -> LoadingScreen()
        is UiState.Success -> SuccessScreen(uiState.data)
        is UiState.Error -> ErrorScreen(uiState.message)
    }
}
Enter fullscreen mode Exit fullscreen mode

Error Handling with UiState

Manage loading, success, and error states:

sealed class UiState {
    object Loading : UiState()
    data class Success(val data: List<Item>) : UiState()
    data class Error(val message: String) : UiState()
}

class MyViewModel : ViewModel() {
    private val _uiState = MutableStateFlow<UiState>(UiState.Loading)
    val uiState: StateFlow<UiState> = _uiState.asStateFlow()

    fun loadData() {
        viewModelScope.launch {
            try {
                val data = fetchData()
                _uiState.value = UiState.Success(data)
            } catch (e: Exception) {
                _uiState.value = UiState.Error(e.message ?: "Unknown error")
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Mastering coroutines and Flow transforms you into an async programming expert.

8 Android app templates available: Gumroad

Top comments (0)