Kir*_*tov 11 android kotlin kotlin-extension kotlin-android-extensions kotlinx.coroutines
有没有任何奇特的方法来实现debounce
Kotlin Android的逻辑?
我没有在项目中使用Rx.
Java中有一种方法,但它对我来说太大了.
Chr*_*ute 19
对于 a 内部的简单方法ViewModel
,您可以在 中启动一个作业viewModelScope
,跟踪该作业,如果在作业完成之前出现新值,则取消它:
private var searchJob: Job? = null
fun searchDebounced(searchText: String) {
searchJob?.cancel()
searchJob = viewModelScope.launch {
delay(500)
search(searchText)
}
}
Run Code Online (Sandbox Code Playgroud)
mas*_*wok 18
我使用的是callbackFlow和防抖动从科特林协同程序来实现去抖动。例如,要实现按钮单击事件的去抖动,请执行以下操作:
创建一个扩展方法Button
来产生一个callbackFlow
:
fun Button.onClicked() = callbackFlow<Unit> {
setOnClickListener { offer(Unit) }
awaitClose { setOnClickListener(null) }
}
Run Code Online (Sandbox Code Playgroud)
订阅您的生命周期感知活动或片段中的事件。以下代码段每 250 毫秒消除一次点击事件:
buttonFoo
.onClicked()
.debounce(250)
.onEach { doSomethingRadical() }
.launchIn(lifecycleScope)
Run Code Online (Sandbox Code Playgroud)
SAN*_*NAT 10
我从堆栈溢出的旧答案中创建了一个扩展函数:
fun View.clickWithDebounce(debounceTime: Long = 600L, action: () -> Unit) {
this.setOnClickListener(object : View.OnClickListener {
private var lastClickTime: Long = 0
override fun onClick(v: View) {
if (SystemClock.elapsedRealtime() - lastClickTime < debounceTime) return
else action()
lastClickTime = SystemClock.elapsedRealtime()
}
})
}
Run Code Online (Sandbox Code Playgroud)
使用以下代码查看 onClick:
buttonShare.clickWithDebounce {
// Do anything you want
}
Run Code Online (Sandbox Code Playgroud)
您可以使用kotlin协同程序来实现这一目标. 这是一个例子.
请注意,协程在kotlin 1.1+上是实验性的,并且可能会在即将推出的kotlin版本中进行更改.
自Kotlin 1.3发布以来,协同程序现已稳定.
感谢https://medium.com/@pro100svitlo/edittext-debounce-with-kotlin-coroutines-fd134d54f4e9和/sf/answers/3500521741/,我编写了以下代码:
private var textChangedJob: Job? = null
private lateinit var textListener: TextWatcher
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
textListener = object : TextWatcher {
private var searchFor = "" // Or view.editText.text.toString()
override fun afterTextChanged(s: Editable?) {}
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
val searchText = s.toString().trim()
if (searchText != searchFor) {
searchFor = searchText
textChangedJob?.cancel()
textChangedJob = launch(Dispatchers.Main) {
delay(500L)
if (searchText == searchFor) {
loadList(searchText)
}
}
}
}
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
editText.setText("")
loadList("")
}
override fun onResume() {
super.onResume()
editText.addTextChangedListener(textListener)
}
override fun onPause() {
editText.removeTextChangedListener(textListener)
super.onPause()
}
override fun onDestroy() {
textChangedJob?.cancel()
super.onDestroy()
}
Run Code Online (Sandbox Code Playgroud)
我没有包括coroutineContext
在这里,所以如果没有设置的话,它可能不会起作用。有关信息,请参阅使用Kotlin 1.3在Android中迁移到Kotlin协程。
小智 7
我创建了一个要点与启发3个防抖动运营商这个优雅的解决方案,从帕特里克,我增加了两个类似的情况:throttleFirst
和throttleLatest
。这两者都是非常相似,他们RxJava类似物(throttleFirst,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)
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
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)
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
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)
}
}
}
Run Code Online (Sandbox Code Playgroud)
所有这些运算符均可按如下方式使用:
val onEmailChange: (String) -> Unit = throttleLatest(
300L,
viewLifecycleOwner.lifecycleScope,
viewModel::onEmailChanged
)
emailView.onTextChanged(onEmailChange)
Run Code Online (Sandbox Code Playgroud)
一个更简单通用的解决方案是使用一个函数,该函数返回执行反跳逻辑的函数,并将其存储在val中。
fun <T> debounce(delayMs: Long = 500L,
coroutineContext: CoroutineContext,
f: (T) -> Unit): (T) -> Unit {
var debounceJob: Job? = null
return { param: T ->
if (debounceJob?.isCompleted != false) {
debounceJob = CoroutineScope(coroutineContext).launch {
delay(delayMs)
f(param)
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
现在可以将其与:
val handleClickEventsDebounced = debounce<Unit>(500, coroutineContext) {
doStuff()
}
fun initViews() {
myButton.setOnClickListener { handleClickEventsDebounced(Unit) }
}
Run Code Online (Sandbox Code Playgroud)
使用标签似乎是一种更可靠的方法,尤其是在使用RecyclerView.ViewHolder
视图时。
例如
fun View.debounceClick(debounceTime: Long = 1000L, action: () -> Unit) {
setOnClickListener {
when {
tag != null && (tag as Long) > System.currentTimeMillis() -> return@setOnClickListener
else -> {
tag = System.currentTimeMillis() + debounceTime
action()
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
用法:
debounceClick {
// code block...
}
Run Code Online (Sandbox Code Playgroud)
@大师作品,
很好的答案。这是我使用 EditText 实现的动态搜索栏。这提供了巨大的性能改进,因此搜索查询不会立即对用户文本输入执行。
fun AppCompatEditText.textInputAsFlow() = callbackFlow {
val watcher: TextWatcher = doOnTextChanged { textInput: CharSequence?, _, _, _ ->
offer(textInput)
}
awaitClose { this@textInputAsFlow.removeTextChangedListener(watcher) }
}
Run Code Online (Sandbox Code Playgroud)
searchEditText
.textInputAsFlow()
.map {
val searchBarIsEmpty: Boolean = it.isNullOrBlank()
searchIcon.isVisible = searchBarIsEmpty
clearTextIcon.isVisible = !searchBarIsEmpty
viewModel.isLoading.value = true
return@map it
}
.debounce(750) // delay to prevent searching immediately on every character input
.onEach {
viewModel.filterPodcastsAndEpisodes(it.toString())
viewModel.latestSearch.value = it.toString()
viewModel.activeSearch.value = !it.isNullOrBlank()
viewModel.isLoading.value = false
}
.launchIn(lifecycleScope)
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
5831 次 |
最近记录: |