Hi, I want to use the `select` clause to select be...
# coroutines
l
Hi, I want to use the
select
clause to select between two user inputs (two button clicks). Should I implement the select clause myself in an extension function, or should I transform the button clicks to a channel, and then use the already existing select clause implementations?
g
Channel implementation would be probably more heavyweight than just 2 callbacks, but at least it already works
g
@gildor heavyweight handling button clicks? how many million clicks per second do you need?
d
I'd say use an extension function. Channel would be be overkill.
l
Is anyone aware of a digest example on how to make a select clause implementation? The Channel implementation is a lot of code for me to see clearly how I should do it
g
Each channel creates more objects and each callback handling involves allocations and atomic usages, because channel is multi-thread abstraction Of course, on practice you will not see difference, my point that just for 2 callbacks you can provide more efficient and simple implementation
l
BTW, performance doesn't need to be optimal in my case, it's an internal TornadoFx app that needs to register some devices
g
@louiscad Depends on API which you want to get, I don’t see why you need coroutines in this case
in general, just subscribe on both callbacks and call another callback, nothing trickt
l
It's not that I need coroutines, but I want to make the whole code sequential. I have a
UserAction
sealed class hierarchy that I want to return from a suspend function implemented in the UI code
g
Copy code
fun onClick(v1: View, v2: View, onClick: (View) -> Unit) {
    v1.setOnClickListener {
        onClick(it)
    }
    v2.setOnClickListener { 
        onClick(it)
    }
}
If you want to use coroutines, use
suspendCoroutine
instead of onClick lambda
l
You're right,
suspendCoroutine
may be enough for my use case, I was over-complicating things. Thanks for your insight!
d
Instead of a channel, why not use a Deferred.
g
Something like this:
Copy code
suspend fun awaitClick(v1: View, v2: View): View {
    return suspendCancellableCoroutine { cont ->
        val onClick: (View) -> Unit = {
            cont.resume(it)
        }
        // Not sure about this part, but probably make sense
        cont.invokeOnCancellation {
            v1.setOnClickListener(null)
            v2.setOnClickListener(null)
        }
        v1.setOnClickListener(onClick)
        v2.setOnClickListener(onClick)
    }
}
👍 1
Or even:
Copy code
suspend fun List<View>.awaitClick(): View {
    return suspendCancellableCoroutine { cont ->
        val onClick: (View) -> Unit = {
            cont.resume(it)
        }
        // Not sure about this part, but probably make sense
        cont.invokeOnCancellation {
            forEach { view -> 
                  view.setOnClickListener(null)
            }
        }
        forEach { view ->
            view.setOnClickListener(onClick)
        }
    }
}
👍 1
l
It's a bit more complex still, as I want to disabled the buttons as soon as one is clicked, plus the user may abandon something that happens next, where I'd need to enable back both buttons and wait for click on one again, but I think I'll figure it out.
g
Still can be handled using the same approach
l
Yes, that's why I put a thumbs up on your snippet
👍 1
g
sorry. fixed example with
List<View>
l
I saw the mistake for this one haha 😉
🙈 1
z
@louiscad if you're still looking for a simpler select clause implementation, I wrote a gist a while back: https://gist.github.com/zach-klippenstein/fa4366388295282fa409c5085abada23
👍 1
l
Thank you @Zach Klippenstein (he/him) [MOD], while I could do without select clause thanks to Andrey's help, it's still interesting, and it may help for future use cases! 👍
👍 1