https://kotlinlang.org logo
Title
s

svenjacobs

01/20/2020, 7:36 AM
Hey, I'm wondering if there is an operator on
Flow
that achieves the following: If the Flow has not produced at least one value in a given timeframe (x miliseconds), produce a default value followed by any values the Flow might produce afterwards. In contrast to a solution with
debounce
however, if the Flow has produced a value before the timeframe, the default value will just be ignored and the value will be emitted immediatly.
Something like a
delayedDefault
😉
I built something myself but I'm not sure if this is the best solution 😁
fun <T> Flow<T>.delayedDefault(
    defaultAfter: Long,
    defaultValue: () -> T
): Flow<T> =
    channelFlow {
        val job = launch {
            delay(defaultAfter)
            offer(defaultValue())
        }

        collect {
            job.cancel()
            offer(it)
        }
    }
e

elizarov

01/20/2020, 9:45 AM
Looks good to me. However, it would be safer to use
send(defaultValue())
just in case somebody does
delayedDefault(…).buffer(0)
.
👍🏼 1
s

svenjacobs

01/20/2020, 9:45 AM
Okay, thanks for the feedback from the expert 👍🏼 😉
e

elizarov

01/20/2020, 9:47 AM
You should also add one more
job.cancel()
after collect, so that it does not wait in the corner case of empty flow (
flowOf().delayedDefault(…)
)
s

svenjacobs

01/20/2020, 9:47 AM
Oh, right!
e

elizarov

01/20/2020, 9:47 AM
Unless you want delay+default in this case, too
s

svenjacobs

01/20/2020, 9:48 AM
Should I also use
send()
inside
collect
?
e

elizarov

01/20/2020, 9:48 AM
Yes, that, too
s

svenjacobs

01/20/2020, 9:49 AM
Cancelling an already cancelled
Job
will do nothing, right? No exception will be thrown?
e

elizarov

01/20/2020, 9:50 AM
Yes. It is perfectly fine and it is quite fast, too.
👍🏼 3