1

Based on this post throttleFirst function:

fun <T> throttleFirst(
    skipMs: Long = 700L,
    scope: CoroutineScope = viewModelScope,
    action: (T) -> Unit
): (T) -> Unit {
    var throttleJob: Job? = null
    return { param: T ->
        if (throttleJob?.isCompleted != false) {
            throttleJob = coroutineScope.launch {
                destinationFunction(param)
                delay(skipMs)
            }
        }
    }
}

I'm using it like this:

View

<Button
    android:onClick="@{viewModel.myClickListener}"
.../>

ViewModel:

fun myClickListener() = View.OnClickListener { _ ->
    throttleClick(clickAction = {
        //do things
    })
}

BaseViewModel:

protected fun throttleClick(millis: Long = 700L, clickAction: (Unit) -> Unit): (Unit) -> Unit  {
    throttleFirst(millis, scope = viewModelScope, action = clickAction)
}

But nothing happens, the clickAction is not reached. While debugging, step-by-step ends when it hits return { param: T -> and that returning function (throttleJob?.isCompleted... code) is never called.
What am I doing wrong?

EDIT with the help from Patrick the final solution is:

ViewModel

private val myThrottleClick = throttleClick(clickAction = {
    //do things
})

fun myClickListener() = View.OnClickListener { myThrottleClick(Unit) }

BaseViewModel

protected fun throttleClick(millis: Long = 700L, clickAction: (Unit) -> Unit): (Unit) -> Unit {
    return throttleFirst(millis, action = clickAction)
}
GuilhE
  • 11,591
  • 16
  • 75
  • 116

1 Answers1

1

Your throttleFirst function makes a click listener, so you must store it in a val outside of your click listeners scope. i.e.

val clickListener = throttleFirst { doStuff() }

fun myClickListener() = View.OnClickListener { _ -> clickListener() }

You may be able to do away with the myClickListener function entirely and just reference clickListener in xml.

Patrick Jackson
  • 18,766
  • 22
  • 81
  • 141
  • Ok got it, only missing one thing, `clickListener()` asks me for parameter. I would like to use Unit but I can't instantiate "void", so how do you suggest I solve this minor detail? – GuilhE Dec 20 '19 at 13:28
  • You can remove the parame from the clickAction. clickAction: () -> Unit. Alternatively you can pass Unit as a param. – Patrick Jackson Dec 20 '19 at 13:38
  • I'll use the second approach because I don't want to change the `throttleFirst` function, instead create a "proxy/helper" `throttleClick` to use it. That said, the second approach is the one to follow :) I was being dumb because I was calling clickListener(Unit()) instead of clickListener(Unit)... ^^ thanks a lot Patrick! – GuilhE Dec 20 '19 at 14:10