https://kotlinlang.org logo
Title
b

bbaldino

12/02/2020, 8:34 PM
Is there a way to wait for an element from a flow with some timeout? Like to emit either 1) whatever is sent on the wrapped flow or 2) something else if the wrapped flow doesn't produce an element within some time period?
Pretty sure this does what I'm looking for, but I had to wrap the flow in a channel and use select. Seems like there might be a better way? https://pl.kotl.in/7N9abgpvp
b

bezrukov

12/02/2020, 9:38 PM
I believe onStart+transformLatest+delay should do the trick, and even may look nice 🙂 (but it will use channel under the hood anyway)
Something like: flow.onStart { emit(null) } .transformLatest { if (it != null) emit(it) delay(500) emit(42) } (didn't test it)
b

bbaldino

12/02/2020, 9:40 PM
Oh interesting! That's a good idea
I found this post (https://github.com/Kotlin/kotlinx.coroutines/issues/1183) and have been playing with this:
fun <T> Flow<T>.withDefaultAfterTimeout(default: T, timeoutMs: Long): Flow<T> = flow {
    coroutineScope { // delimit a scope in which flow is running
        val channel = produceIn(this) // run flow in the scope
        while (isActive) {
            val result = withTimeoutOrNull(timeoutMs) {
                select<T> {
                    channel.onReceive { it }
                }
            } ?: default
            emit(result)
        }
    }
}
Why is the
flow.onStart { emit(null) }
needed?
b

bezrukov

12/02/2020, 9:49 PM
Otherwise there will be no timeout before first item appears
b

bbaldino

12/02/2020, 9:49 PM
ah
Ah, one issue with this method is that I lose elements if they come too close together Ignore me, I just didn't set the replay value on the underlying flow.