androidhigher-order-functionskotlin-coroutinescoroutinescopeandroidx-lifecycle

Coroutine doens't start?


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

Solution

  • 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.