What's the best way for me to collect this stateFl...
# compose
c
What's the best way for me to collect this stateFlow boolean just to log it? Option 1
Copy code
@Composable
fun App() {
    LaunchedEffect(Unit) {
        applicationScope.launch {
            connection?.isConnected?.collectLatest {
                Logger.i { "connected? $it" }
            } } }
no logs Option 2
Copy code
@Composable
fun App() {
        applicationScope.launch {
            connection?.isConnected?.collectLatest {
                Logger.i { "connected? $it" }
            } } }
I get double logs
j
Option 2 is just wrong. You'll get a new coroutine for each recomposition.
👍 1
Side effects should not be put directly in a composition
Seems like something you might want to hoist outside of the composition entirely
👀 1
☝️ 1
s
Option 1 may not execute the log if your states are null (
connection?.isConnected?.
) on the first frame of composition
👀 1
c
I tried hoisting out of the App composable entirely and just having it in the top level of my App.kt file... but that also doesn't work. I guess I would need to do it in the
init {}
block of App.kt?
l
Would it make sense to use connection?.isConnected as the key for LaunchedEffect? That would also allow you to update if the value changes.
j
That only works if connection is observable by Compose
c
so i did leave that out
var connection by mutableStateOf<Connection?>(null)
j
well that only means that changes to the connection instance are observable, not changes to its
isConnected
value
c
Okay. so this is kinda ugly... but only single instance of logs... so it works 🎉
Copy code
@Composable
fun App() {
    LaunchedEffect(Unit) {
        snapshotFlow { connection }
            .collectLatest { conn ->
                conn?.isConnected?.collectLatest {
                    Logger.i { "connected? $it" }
                }
            }
    }
to follow jakes advice though... I am a bit more curious on where I could do this work outside of the composable...
And just to be clear... this IS fine to do in a composable right?
Copy code
val connected = connection?.isConnected?.collectAsState()
j
only if
isConnected
returns the same instance each time it's called
if you create a new flow instance each time it's called, then you will constantly be collecting and canceling coroutines
c
Hm. Not sure if I follow 100% my setup is as such
Copy code
var connection by mutableStateOf<Connection?>(null)
and then
Copy code
class Connection {
    private val _isConnected = MutableStateFlow(false)
    val isConnected = _isConnected.asStateFlow()
I guess since private val _isConnected = MutableStateFlow(false) is val then I should be good
j
well no, it's because
isConnected
is a
val
without a
get()
that you're good.
However, I would do
val isConnected: StateFlow<Boolean> get() = _isConnected
👀 1
asStateFlow()
is almost always pointless
today i learned 1
📝 3
c
cool. making progress. I do still want to move this outside of the Composable, But I'm in a CMP (android+ios) app and basically this is my first "entry point" that is shared. so im trying to do this initial logging in one place
also actually...
However, I would do val isConnected: StateFlow<Boolean> get() = _isConnected
wouldn't that mean that now the consumer can edit this?
j
no,
StateFlow
is not writable
c
I updated private val _isConnected = MutableStateFlow(false) val isConnected = _isConnected.asStateFlow() to private val _isConnected = MutableStateFlow(false) val isConnected: StateFlow<Boolean> get() = _isConnected though
oh jeez.
I didn't put the specific type.
okay. now that makes sense.