Can I use a `StateFlow` in a `select` statement? T...
# coroutines
r
Can I use a
StateFlow
in a
select
statement? The IDE doesn't seem to think
onAwait
exists.
r
Yes, via a Channel
Copy code
coroutineScope {
   val channel1 = stateFlow1.produceIn(this)
   val channel2 = stateFlow2.produceIn(this)

   // often whileSelect when dealing with streams
   select {
      channel1.onReceiveCatching { result -> }
      channel2.onReceiveCatching { result -> }
   }

   // Remember to close
   channel1.close()
   channel2.close()
}
There's not much point in an
onAwait
for
StateFlow
as it always has a value immediately accessible with
.value
- Unless you are combining it with
filter
in which case you could do
Copy code
coroutineScope {
   
   val async1 = async { stateFlow1.filterNotNull().first() } 
   val async2 = async { stateFlow2.filterNotNull().first() } 

   select {
      async1.onAwait { result -> }
      async2.onAwait { result -> }
   }
}
r
Ah, nice, makes sense.
So in case I wanna wait for one of the three things to happen, this could work?
Copy code
val transientToStandby = tvState.filter { it is TVState.TransientToStandby }.produceIn(this)
        val standby = tvState.filter { it is TVState.Standby }.produceIn(this)
        val timeout = produce<Unit> { delay(5.seconds); send(Unit) }
        select<Unit> {
            transientToStandby.onReceive {
            }
            standby.onReceive {
            }
            timeout.onReceive {
            }
        }
r
yes it would, but a simpler approach would be
Copy code
when (val result = withTimeoutOrNull(5.seconds) {
                    tvState.filter { it is TVState.TransientToStandby || it is TVState.Standby }.first()
                }) {
                    TVState.TransientToStandby -> {}
                    TVState.Standby -> {}
                    null -> {}
                }
select
also provides an
onTimeout
method if you don't want to create your own
produce
block
r
ah neat. I think I prefer the
select
version, reads better.