I want to debounce the items sent to a shared flow, and consume them after that. Something like this:
private var flow = MutableSharedFlow()
suspend fun search(query: String): Flow<Result> {
flow.emit(query)
return flow.debounce(1000).map{ executeSearch(it) }
}
The event that initiates the search is a user writing on a field. For each character, the search function is called. So I want to get a debounced result, to avoid many queries to the server. It looks like the debounce operator returns a different flow instance each time, so that all the queries end up invoking the executeSearch() function, without dropping any of them as you could expect by using a debounce operator. How can I achieve a functionality like this, so that a client can invoke a function that returns a flow with debounced results?
CodePudding user response:
You can try something like this:
private var flow = MutableSharedFlow()
init {
flow.debounce(1000)
.collect {
val result = executeSearch(it)
// Process the result (maybe send to the UI)
}
}
suspend fun search(query: String) {
flow.emit(query)
}
CodePudding user response:
With two flows you could do it like this. One backing flow takes all the search inputs, and the second is a debounce version of it that runs the query. The search function doesn’t return a flow because the Flow is already available as a property and we aren’t creating new ones for each input.
private val searchInput = MutableSharedFlow<String>()
val searchResults = searchInput.debounce(1000)
.map { executeSearch(it) }
.shareIn(viewModelScope, SharingStarted.Eagerly)
fun submitSearchInput(query: String) {
searchInput.tryEmit(query)
}
You could alternatively do it with jobs that you extinguish when new inputs come in:
private val searchJob: Job? = null
private val _searchResults = MutableSharedFlow<SearchResultType>()
val searchResults = _searchResults.asSharedFlow()
fun submitSearchInput(query: String) {
searchJob?.cancel()
searchJob = viewModelScope.launch {
delay(1000)
_searchResults.emit(executeSearch(query))
}
}
