我创建了一个gist https://gist.github.com/Terenfear/a84863be501d3399889455f391eeefe5三个去抖运算符的灵感来自于这个优雅的解决方案 https://stackoverflow.com/a/55802898/5102726 from Patrick https://stackoverflow.com/users/751581/patrick我又添加了两个类似的案例:throttleFirst
and throttleLatest
。这两个都与它们的 RxJava 类似物非常相似(油门第一 https://github.com/ReactiveX/RxJava/wiki/Filtering-Observables#throttlefirst, 油门最新 https://github.com/ReactiveX/RxJava/wiki/Filtering-Observables#throttlelatest).
throttleLatest
作品类似于debounce
但它按时间间隔运行并返回每个时间间隔的最新数据,这允许您在需要时获取和处理中间数据。
fun <T> throttleLatest(
intervalMs: Long = 300L,
coroutineScope: CoroutineScope,
destinationFunction: (T) -> Unit
): (T) -> Unit {
var throttleJob: Job? = null
var latestParam: T
return { param: T ->
latestParam = param
if (throttleJob?.isCompleted != false) {
throttleJob = coroutineScope.launch {
delay(intervalMs)
latestParam.let(destinationFunction)
}
}
}
}
throttleFirst
当您需要立即处理第一个调用,然后跳过后续调用一段时间以避免出现不良行为(例如,避免在 Android 上启动两个相同的活动)时,此功能非常有用。
fun <T> throttleFirst(
skipMs: Long = 300L,
coroutineScope: CoroutineScope,
destinationFunction: (T) -> Unit
): (T) -> Unit {
var throttleJob: Job? = null
return { param: T ->
if (throttleJob?.isCompleted != false) {
throttleJob = coroutineScope.launch {
destinationFunction(param)
delay(skipMs)
}
}
}
}
debounce
有助于检测一段时间内没有新数据提交时的状态,有效地允许您在输入完成时处理数据。
fun <T> debounce(
waitMs: Long = 300L,
coroutineScope: CoroutineScope,
destinationFunction: (T) -> Unit
): (T) -> Unit {
var debounceJob: Job? = null
return { param: T ->
debounceJob?.cancel()
debounceJob = coroutineScope.launch {
delay(waitMs)
destinationFunction(param)
}
}
}
所有这些运算符都可以按如下方式使用:
val onEmailChange: (String) -> Unit = throttleLatest(
300L,
viewLifecycleOwner.lifecycleScope,
viewModel::onEmailChanged
)
emailView.onTextChanged(onEmailChange)