How would I go about updating this code to be sync...
# coroutines
c
How would I go about updating this code to be synchronous in retrieving that first value?
Copy code
val loggedIn: Flow<Boolean> = prefs.data
    .map { preferences ->
        preferences[authenticated] ?: false
    }
This is my first time working with Flow, so I might be misunderstanding it's usage, but my use case is that when my app starts, I'm reading from
prefs
and I need to know (at the moment the app starts) whether I'm logged in or logged out, but then every time after the first time, I want it to be async. Is there some typical pattern for when you want a flow... BUT you want to have the actual first item in the Flow before you go any further?
j
A
StateFlow
could be an option here. Suspend until you get the initial value and create your
StateFlow
with the initial value, then launch a coroutine to update the
StateFLow
c
@uli and @Joffrey I see that I can chain
Copy code
.stateIn()
onto my code above, but the two issues I have with that is 1. I need a scope... but this should be a singleton so I guess I would just use GlobalScope? 2. When I add stateIn I get this error
Suspend function 'stateIn' should be called only from a coroutine or another suspend function
j
For problem one, maybe it's a rare occurrence where
GlobalScope
would be OK to use. However, should this really be in a singleton? Isn't there any sort of lifecycle you would like this to be tied to? It seems to me that the consumers of this state could actually be the ones providing the scope on the fly (after all, do you really need to listen to preference changes when no one is here to do anything with the value?).
For problem 2, this is because you need to somehow wait for the first value to come, so this method suspends to indicate that it waits. You need to either provide a scope in which to wait, or block the current thread to do so with
runBlocking
c
Alright, I tried this
Copy code
val loggedIn: StateFlow<Boolean> =
        runBlocking {
            prefs.data
                .map { preferences ->
                    preferences[isAuthenticated] ?: false
                }.stateIn(MainScope())
        }
and to collect
Copy code
vm.loggedInState.collectAsState()
but I seem to just be blocked? i.e. my app just hangs on launch on the splash screen lol
j
If you use
runBlocking
you need to be very careful which thread you're blocking. Using this during app initialization likely blocks the main thread. I don't know how the initial preferences are supposed to be fetched (haven't done Android stuff in a long time) but if this happens on the main thread too you might be creating a deadlock here
c
Yeah. Its really only the first state which should be blocking. I guess there's no good way to say "block the first time only"
u
Try with stateIn and an unconfined dispatcher
Just a wild guess
o
Have a seperate flow.first() call perhaps
c
Yeah. Thanks what I basically landed on. 😅
It's not the cleanest looking code, but it works and does make sense to someone reading it.