Skip to content

Instantly share code, notes, and snippets.

@mahdiPourkazemi
Created August 11, 2025 19:20
Show Gist options
  • Save mahdiPourkazemi/c38d319f8ed8774a3573872f39fc7d23 to your computer and use it in GitHub Desktop.
Save mahdiPourkazemi/c38d319f8ed8774a3573872f39fc7d23 to your computer and use it in GitHub Desktop.
fiveFlowUseFullPattern
The One-Shot Operation as a Cold Stream
//########################################################################
class MyViewModel(private val repository: DataRepository) : ViewModel() {
private val _data = MutableStateFlow<UiState>(UiState.Loading)
val data: StateFlow<UiState> = _data
fun fetchData() {
viewModelScope.launch {
try {
_data.value = UiState.Success(repository.fetchSomeData())
} catch (e: Exception) {
_data.value = UiState.Error(e)
}
}
}
}
//#############################into this#######################################
class MyViewModel(private val repository: DataRepository) : ViewModel() {
val data: StateFlow<UiState> = flow {
// This block is the coroutine scope
emit(repository.fetchSomeData())
}
.map { result -> UiState.Success(result) } // Transform data to UI state
.catch { e -> emit(UiState.Error(e)) } // Handle errors declaratively
.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5000),
initialValue = UiState.Loading
)
}
//########################################################################
Callbacks with callbackFlow
fun Context.locationFlow(): Flow<Location> = callbackFlow {
val locationListener = object : LocationListener {
override fun onLocationChanged(location: Location) {
// Offer the value to the flow's collector
trySend(location).isSuccess
}
// Other listener methods...
}
val locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
locationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER, 5000, 10f, locationListener
)
// This is the magic part
awaitClose {
// This block is executed when the flow is cancelled
locationManager.removeUpdates(locationListener)
}
}
//########################################################################
The Search Bar with debounce and flatMapLatest
// In your ViewModel
val searchQuery = MutableStateFlow("")
val searchResults: Flow<List<Result>> = searchQuery
.debounce(300) // Wait for user to stop typing for 300ms
.filter { query -> query.length > 2 } // Only search if query is long enough
.distinctUntilChanged() // Don't re-search for the same text
.flatMapLatest { query -> // The key operator
// Creates a new flow for the network call
// AND cancels the previous one if a new query comes in
api.search(query)
}
.catch {
// Handle network errors for the search
emit(emptyList())
}
//########################################################################
// Define user actions as a sealed class
sealed class LikeAction {
object Increment : LikeAction()
object Decrement : LikeAction()
}
val userActions = MutableSharedFlow<LikeAction>() // A flow of events
val likeCount: StateFlow<Int> = userActions
.scan(0) { currentCount, action -> // Start with 0, and process each action
when (action) {
is LikeAction.Increment -> currentCount + 1
is LikeAction.Decrement -> maxOf(0, currentCount - 1)
}
}
.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5000),
initialValue = 0
)
// From the UI, you would just call:
// viewModel.userActions.tryEmit(LikeAction.Increment)
viewModel.userActions.tryEmit(LikeAction.Increment)
//##############################examole of ^\ ######################################
sealed class LikeAction {
object Increment : LikeAction()
object Decrement : LikeAction()
object Undo : LikeAction()
}
data class LikeState(val count: Int, val history: List<Int>)
val userActions = MutableSharedFlow<LikeAction>()
val likeState: StateFlow<LikeState> = userActions
.scan(LikeState(0, emptyList())) { currentState, action ->
when (action) {
is LikeAction.Increment ->
currentState.copy(
count = currentState.count + 1,
history = currentState.history + currentState.count
)
is LikeAction.Decrement ->
currentState.copy(
count = maxOf(0, currentState.count - 1),
history = currentState.history + currentState.count
)
is LikeAction.Undo ->
if (currentState.history.isNotEmpty()) {
val last = currentState.history.last()
currentState.copy(
count = last,
history = currentState.history.dropLast(1)
)
} else currentState
}
}
.stateIn(viewModelScope,
SharingStarted.WhileSubscribed(5000),
LikeState(0, emptyList())
)
@mahdiPourkazemi
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment