Flow.debounce – entprellte Live-Suche in Jetpack Compose
Eine Suche, die bei jedem Buchstaben eine Anfrage feuert, überlastet dein Backend. Mit `debounce` auf einem Flow wartest du eine kurze Pause ab und suchst erst dann – ideal fürs Suchfeld.
Tippt jemand „Berlin" in dein Suchfeld, sind das schnell sechs API-Anfragen. Auf einem Flow löst debounce das Problem elegant: Es lässt einen Wert erst durch, wenn eine bestimmte Zeit lang kein neuer nachkommt. Kombiniert mit flatMapLatest bricht eine noch laufende Suche automatisch ab, sobald der Nutzer weitertippt.
Der Query-Flow im ViewModel
import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.flow.*
class SearchViewModel(private val repo: SearchRepository) : ViewModel() {
private val query = MutableStateFlow("")
fun onQueryChange(text: String) { query.value = text }
@OptIn(FlowPreview::class)
val results: StateFlow<List<Hit>> = query
.debounce(300) // erst nach 300 ms Ruhe weiter
.map { it.trim() }
.distinctUntilChanged() // gleicher Text? nicht neu suchen
.filter { it.length >= 2 }
.flatMapLatest { q -> repo.search(q) } // neue Eingabe bricht alte Suche ab
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), emptyList())
}Anbinden in Compose
@Composable
fun SearchScreen(vm: SearchViewModel) {
val text by vm.query.collectAsStateWithLifecycle() // falls query öffentlich
val hits by vm.results.collectAsStateWithLifecycle()
OutlinedTextField(value = text, onValueChange = vm::onQueryChange, label = { Text("Suche") })
LazyColumn { items(hits) { hit -> Text(hit.title) } }
}Jetzt läuft pro Tipp-Pause genau eine Suche, und veraltete Ergebnisse können dir nicht mehr dazwischenfunken. debounce ist noch als @FlowPreview markiert – deshalb das @OptIn.
Solche reaktiven Suchen baue ich regelmäßig in Android-Apps ein. Wenn du eine App in Kotlin & Compose planst, melde dich über bymw.de.
Quellen
Du brauchst mehr als ein Snippet?
Ich entwickle Android-Apps in Kotlin und moderne Websites für Selbstständige und kleine Unternehmen — von der ersten Idee bis zum Release.
Projekt anfragen →Verwandte Snippets
rememberCoroutineScope – Coroutinen aus einem Klick in Jetpack Compose starten
LaunchedEffect ist super für Effekte beim Zusammenbau der UI – aber wie startest du eine Coroutine, wenn der Nutzer auf einen Button tippt? Dafür gibt es rememberCoroutineScope. Ich zeige den Unterschied und ein typisches Snackbar-Beispiel.
withTimeout – hängende Coroutines nach X Sekunden abbrechen
Ein Netzwerkaufruf, der ewig hängt, blockiert deinen Ladezustand für immer. Mit `withTimeout` gibst du einer Coroutine eine Frist – läuft sie ab, bricht Kotlin sie sauber ab.
value class in Kotlin – typsichere IDs ohne Extra-Kosten zur Laufzeit
Ein `String` für die Nutzer-ID, ein `String` für die Bestell-ID – und schon vertauschst du sie irgendwann. Mit `@JvmInline value class` bekommst du echte, unverwechselbare Typen, die zur Laufzeit trotzdem nur der nackte Wert sind. Kein Wrapper-Objekt, keine Bremse.