Is there any dangers of using .stateIn Flow extens...
# coroutines
k
Is there any dangers of using .stateIn Flow extension with custom background CoroutineScope inside your ViewModel?
j
It mostly has to do with the lifetime you want to give the coroutines launched in it. If they should live while the
ViewModel
lives, you probably should use
viewModelScope
. If they should outlive the
ViewModel
, then it would be appropriate to use a custom scope for that. The main "danger" in my opinion is that you have to manually control the lifetime of that scope (in other words, don't forget to
cancel()
it when appropriate)
k
If StateFlow is no longer collected, does custom CoroutineScope cancel itself?
j
No. If you use the
CoroutineScope()
factory function, you have to cancel it manually in any case (the goal is to prevent coroutines from leaking if one doesn't end properly).
k
Thanks
j
That being said, if you use a
StateFlow
, you most likely should use
viewModelScope
instead of a custom one, because you're not interested in that state outside of the viewmodel right?
k
Yes, however, I wanted to do the work on a background thread. From my understading viewModelScope is on Main thread.
j
That's a different story. The thread used is defined by the
Disptacher
, not the scope per se. The scope provides a default dispatcher, but all coroutine builders accept a parameter to launch coroutines on a different dispatcher (e.g.
scope.launch(<http://Dispatchers.IO|Dispatchers.IO>)
). In the case of a flow, you could use
myFlow.flowOn(<http://Dispatchers.IO|Dispatchers.IO>).stateIn(viewMoedlScope)
(of course you can replace
<http://Dispatchers.IO|Dispatchers.IO>
by whichever dispatcher you want to use here)
k
So in that case, flow calculation will be done inside of the (e.g.) IO, while StateFlow will be on Main thread?
Or
viewModelScope
will inherit previously declared scope inside
flowOn
j
flowOn
only affects preceding steps in the flow, the context is always preserved on the collector side. In short, everything before
.flowOn
in the flow definition will run on IO dispatcher, and everything between
flowOn
and
stateIn
will run on whichever default dispatcher is provided by
viewModelScope
(most likely Main as you said). There is nothing between
flowOn
and
stateIn
in the provided snippet, so nothing from this flow will actually run on Main here. However, the collectors of the resulting flow will run their
collect
on whatever dispatcher they are using.
k
Thanks!
n
myFlow.stateIn(viewModelScope + <http://Dispatchers.IO|Dispatchers.IO>)
You can use
+
to create a new scope with the same lifetime but a different dispatcher (or any context element, only
Job
controls lifetime). This will run the flow and collect on the
IO
dispatcher so there is no dispatch just to update the StateFlow.
🙌 1
👍 1
j
Nice one, didn't even think of using
+
here 🙂
This will run the flow and collect on the 
IO
 dispatcher
No, not the collectors. All flows must preserve the collector's context, and this is also true if you use
stateIn(viewModelScope + <http://Dispatchers.IO|Dispatchers.IO>)
. The collectors will execute in whichever context there are called from, not on the dispatcher specified here.
n
stateIn
starts a new coroutine. It collects using the specified scope.
j
Ah sorry I misunderstood what you wrote then. I was talking about the StateFlow's collectors in my previous message