So I've been exploring MVI with Kotlin Flows, basically MutableSharedFlow for Events and MutableStateFlow for States. but I have a problem adding logic to control the text changes event emissions, writing this in a human way would be something like that.
Observe text changes and only search for the latest word written within half of a second.
So if the user removes or adds letters I only take the search for the latest word after half-second passed.
My attempt to achieve this was by writing the following, here I subscribe to events
events.flatMapConcat { it.eventToUsecase() }
.onEach { _states.value = it }
.launchIn(viewModelScope)
And I map each event to a use case using this function:
private fun SearchScreenEvent.eventToUsecase(): Flow<SearchState> {
return when (this) {
is SearchClicked -> searchUsecase(this.query)
is SearchQueryChanged ->
flowOf(this.query)
.debounce(500)
.flatMapConcat { searchUsecase(it) }
}
}
I know that I have to control the event itself, but how to control only the SearchQueryChanged event independently. with RxJava I was using Publish
and switchMap
operators is there something like this with Flow.
CodePudding user response:
debounce()
can take a lambda parameter that determines the latency per item, so I think this will work:
events.debounce {
when (it) {
is SearchClicked -> 0L
is SearchQueryChanged -> 500L
}
}
.flatMapConcat { searchUsecase(it.query) }
.onEach { _states.value = it }
.launchIn(viewModelScope)
CodePudding user response:
@Tenfour04 Solution will work, but it shows a design problem, so I have to take care of the flow logic in two places now, may be more, so I've posted the same question in slack and someone guides me to redesign my flow as follow:
merge( searchCurrentQuery(),
searchWhileTyping(),
updateUiSearchText())
.flatMapMerge { it.toUsecase() }
.onEach { _states.value = it }
.launchIn(viewModelScope)
By seperating events and using merge to add them into the stream, now I could control each Flow of them as I want.