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
Flowis more powerful for reactive programming, allowing better control and advanced operators.LiveDatais a lifecycle-aware data holder, andStateFlowcan 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