Kotlin Android debounce

前端 未结 10 825
佛祖请我去吃肉
佛祖请我去吃肉 2020-12-05 11:07

Is there any fancy way to implement debounce logic with Kotlin Android?

I\'m not using Rx in project.

There is a way in Java, but it is too big

10条回答
  •  执笔经年
    2020-12-05 11:09

    I've created a gist with three debounce operators inspired by this elegant solution from Patrick where I added two more similar cases: throttleFirst and throttleLatest. Both of these are very similar to their RxJava analogues (throttleFirst, throttleLatest).

    throttleLatest works similar to debounce but it operates on time intervals and returns the latest data for each one, which allows you to get and process intermediate data if you need to.

    fun  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 is useful when you need to process the first call right away and then skip subsequent calls for some time to avoid undesired behavior (avoid starting two identical activities on Android, for example).

    fun  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 helps to detect the state when no new data is submitted for some time, effectively allowing you to process a data when the input is completed.

    fun  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)
            }
        }
    }
    

    All these operators can be used as follows:

    val onEmailChange: (String) -> Unit = throttleLatest(
                300L, 
                viewLifecycleOwner.lifecycleScope, 
                viewModel::onEmailChanged
            )
    emailView.onTextChanged(onEmailChange)
    

提交回复
热议问题