第 38 课2026.08.24
用户输入搜索词时,每敲一个字符都会产生新值。如果立即查询,容易触发大量无效请求;debounce() 可以等用户短暂停顿后再继续处理。
第 38 课:debounce 处理搜索输入
知识点
使用 Flow 的 debounce() 等待输入稳定后,再向下游发送最新值。
用途
用户输入搜索词时,每敲一个字符都会产生新值。如果立即查询,容易触发大量无效请求;debounce() 可以等用户短暂停顿后再继续处理。
核心概念
debounce(500)表示新值到来后等待 500 毫秒。- 等待期间若又有新值,旧值会被忽略,并从新值重新计时。
- 输入停止后,最新值会被发送给下游。
debounce目前需要使用@OptIn(FlowPreview::class)。- 它只控制值的发送频率,不负责真正执行搜索。
示例代码
下面的 ViewModel 接收界面输入,并暴露已经稳定 500 毫秒的搜索词:
kotlin
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.stateIn
@OptIn(FlowPreview::class)
class SearchViewModel : ViewModel() {
private val query = MutableStateFlow("")
val stableQuery: StateFlow<String> = query
.debounce(500)
.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5_000),
initialValue = "",
)
fun onQueryChange(value: String) {
query.value = value
}
}例如用户在 500 毫秒内依次输入 K、KM、KMP,下游不会收到前两个中间值;停止输入 500 毫秒后,stableQuery 更新为 KMP。
5 分钟练习
把等待时间改为 800 毫秒,并补全下面的代码:
kotlin
val stableQuery: StateFlow<String> = query
.________(________)
.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5_000),
initialValue = "",
)想一想:用户在 800 毫秒内连续输入 Ko、Kot、Kotlin,然后停止输入,最终会发送哪个值?
参考答案
kotlin
val stableQuery: StateFlow<String> = query
.debounce(800)
.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5_000),
initialValue = "",
)最终发送 Kotlin,因为它是等待时间内出现的最新值。
与上一课的联系
上一课的 retryWhen() 在请求失败后控制是否再次尝试;今天的 debounce() 在请求开始前减少无效触发。两者分别从失败恢复和输入频率两个位置,让数据流更稳定。