https://kotlinlang.org logo
Title
j

Joakim Forslund

12/13/2021, 10:01 AM
I have a flow that I use
.collect {}
on, however, I want to wait for a StateFlow/Boolean to be true before the collection can proceed, what is the recommended way of currently handling this? (None of the emits can be dropped, they need to wait for the StateFlow/Boolean to be true and emit as soon as it changes)
s

simon.vergauwen

12/13/2021, 10:04 AM
flow {
   stateFlow.first { it == true }
     
     originalFlow.collect(this)
}
You can create a new flow, that awaits the first
true
signal from
StateFlow
and then it collects the original flow.
j

Joakim Forslund

12/13/2021, 10:56 AM
Thanks for the pointer, i'll check it out
j

Joffrey

12/13/2021, 1:48 PM
@simon.vergauwen I think the
collect()
that is chained after the
first()
call is a mistake/typo,
first()
is already a terminal operator
s

simon.vergauwen

12/13/2021, 1:50 PM
Thank you @Joffrey that is indeed a mistake then, I wrote this from memory.
u

ursus

12/13/2021, 2:22 PM
stateFlow.filter { it == true }.take(1).flatMap { originalFlow }
j

Joakim Forslund

12/13/2021, 9:48 PM
Thanks people
suspend fun <T> Flow<T>.waitForTrue(stateFlow: StateFlow<Boolean>):Flow<T>{
    stateFlow.first { it }
    return this
}
Became the result, which seems kind of silly, but yeah
first
is suspending without being terminating, so it is a way to solve it.
j

Joffrey

12/14/2021, 8:35 AM
The problem is that the operator that you created isn't cold anymore, it has to suspend at the moment it's called, instead of when the flow is collected
j

Joakim Forslund

12/14/2021, 8:37 AM
Is it a problem though? The only real effect I care about in this instance is that it block any
.collect
calls from proceeding?
The data is waiting to be collected is indeed put into a suspended state and will proceed when the stateFlow changes?
s

simon.vergauwen

12/14/2021, 8:51 AM
I’d say it’s a problem since now you’re waiting on stateFlow to constructor the
Flow
which has no influence on the collection.
1
j

Joakim Forslund

12/14/2021, 9:19 AM
And doing:
suspend fun <T> Flow<T>.waitForTrue2(stateFlow: StateFlow<Boolean>): Flow<T> {
    return flow {
        stateFlow.first { it }
        this@waitForTrue2.collect(this)
    }
}
Would then adhere to this?
or must it basically be a replacement for
.collect
all together?
s

simon.vergauwen

12/14/2021, 9:21 AM
No, this is the replacement for
collect
. The lambda inside
flow { }
is executd when you call
collect
. So first it will await the boolean, and then it’ll collect the original flow.
j

Joakim Forslund

12/14/2021, 9:22 AM
Right, it makes sense
j

Joffrey

12/14/2021, 9:23 AM
Your new version is fine (it's basically @simon.vergauwen's initial suggestion as an extension function), however you don't need the
suspend
keyword anymore 😉 Calling this operator immediately constructs the new flow without waiting. Collectors of this flow are the ones that will suspend when actually collecting
☝️ 1
👍 1
j

Joakim Forslund

12/14/2021, 9:27 AM
Allright, thanks for clearing things up 🙂