Cheat sheet for using Kotlin Coroutines with Flow in Jetpack Compose Android

 Here’s a cheat sheet for using Kotlin Coroutines with Flow in Android Jetpack Compose:

1. Basic Setup

To use Flow, ensure you have the following dependencies in your build.gradle:

dependencies {
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0"
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.0"
    implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.3.1"
}

2. Creating a Flow

You can create a Flow using the flow builder:

fun getData(): Flow<String> = flow {
    emit("Loading data...") // Emit a value
    delay(1000)
    emit("Data fetched successfully") // Emit another value
}

3. Collecting Data in Compose

In Jetpack Compose, use LaunchedEffect or collectAsState to collect the Flow and update the UI reactively.

With LaunchedEffect (Ideal for side-effects):

@Composable
fun DataDisplay() {
    val dataFlow = getData()
    
    LaunchedEffect(dataFlow) {
        dataFlow.collect { data ->
            // Handle the data and update UI accordingly
            Log.d("FlowData", data)
        }
    }
}

With collectAsState (Ideal for UI updates):

@Composable
fun DataDisplay() {
    val dataFlow = getData().collectAsState(initial = "Loading...")

    Text(text = dataFlow.value) // Display the collected data
}

4. State and Flow

If you need to expose a Flow inside a ViewModel:

class MyViewModel : ViewModel() {
    private val _dataFlow = MutableStateFlow("Loading...")
    val dataFlow: StateFlow<String> = _dataFlow

    init {
        viewModelScope.launch {
            delay(1000)  // Simulate data loading
            _dataFlow.value = "Data loaded!"
        }
    }
}

5. Flow Operators

Flow provides a set of operators to transform, filter, or combine flows.

map:

fun getUpperCaseData(): Flow<String> {
    return getData().map { it.toUpperCase() }
}

filter:

fun getFilteredData(): Flow<String> {
    return getData().filter { it.contains("Data") }
}

catch:

Handles errors in the flow.

fun safeGetData(): Flow<String> = flow {
    emit("Start fetching data...")
    throw Exception("Error while fetching data")
}.catch { exception ->
    emit("Error: ${exception.message}")
}

collectLatest:

Collect the latest value, cancelling the previous collection if a new value arrives.

LaunchedEffect(Unit) {
    getData().collectLatest { value ->
        // Handle the latest value
    }
}

6. Flow vs LiveData

  • Flow is more powerful for reactive programming, allowing better control and advanced operators.
  • LiveData is a lifecycle-aware data holder, and StateFlow can be used similarly in Compose.

7. Flow for Paging

Paging data can be fetched using a Flow. You can use the Paging library in combination with Flow to stream paginated data.

val pager = Pager(PagingConfig(pageSize = 20)) {
    MyPagingSource()
}.flow.cachedIn(viewModelScope)

8. Using stateIn to Convert Flow to StateFlow

If you need to convert a Flow into a StateFlow, you can use stateIn to collect it in a StateFlow.

val stateFlow = getData().stateIn(viewModelScope, SharingStarted.Lazily, "Initial value")

9. Handling Multiple Flows

You can combine multiple flows using operators like combine or zip.

val flow1 = flowOf("Data 1")
val flow2 = flowOf("Data 2")
val combinedFlow = combine(flow1, flow2) { data1, data2 ->
    "$data1 - $data2"
}

10. Error Handling

Flows provide a way to handle errors using catch and onEach.

fun getDataWithErrorHandling(): Flow<String> = flow {
    emit("Fetching data")
    throw Exception("Data fetch failed")
}.catch { exception ->
    emit("Error: ${exception.message}")
}

11. Timeouts

You can also apply timeouts to a flow, canceling it if it takes too long:

val result = withTimeoutOrNull(2000) {
    flowOf("Data fetched").collect()
}

12. Flow in ViewModel

Example of using Flow in a ViewModel for UI data:

class MyViewModel : ViewModel() {
    private val _myFlow = MutableStateFlow("Initial value")
    val myFlow: StateFlow<String> = _myFlow

    init {
        viewModelScope.launch {
            delay(2000)  // Simulate a delay
            _myFlow.value = "Updated value"
        }
    }
}

This is a basic guide to help you get started with Coroutines and Flow in Jetpack Compose. You can extend these patterns as needed based on the complexity of your application.

0 comments:

Post a Comment