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, andStateFlow
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