I recently read something that I interpreted as be...
# coroutines
d
I recently read something that I interpreted as being bad.
Copy code
suspend fun someFunctionCreatesAFlow(context: Dispatchers.Default): Flow<String> = withContext(context) {
 flow {
    emit(somethingAsAString)
   } 
}
I guess it is because Flows kinda manage their own context with
flow::flowOn()
. Can anybody confirm this?
So I guess this is the right way ... ?
Copy code
suspend fun someFunctionCreatesAFlow(context: Dispatchers.Default): Flow<String> = coroutineScope {
 flow {
    emit(somethingAsAString)
   } .flowOn(context)
}
d
Copy code
suspend fun someFunctionCreatesAFlow(context: Dispatchers.Default): Flow<String> = flow {
    emit(somethingAsAString)
   } .flowOn(context)
d
Ohh well yeah but in my actual use case `somethingAsAString`is of type
suspend CoroutineScope.() -> String
. Therefore I need a scope
o
it's not bad necessarily, but iirc
flow
isn't a suspend function itself, only terminal operations, so it doesn't pass any of the context to the flow. technically that function doesn't need to be suspend at all
d
But I forget to mention sorry
o
if you need a scope, create it inside
flow { }
e.g.
Copy code
flow {
  coroutineScope {
     ...
  }
}
👍🏼 1
l
Don't make is suspending, just use
flowOn
.
1
s
What Louis said. The creation of a Flow has/needs no context/scope. The collector of the Flow, however does need one, and that will be the same scope that is used when your Flow's emitter (that suspend-lambda) is called.
p
If I call
Flow.collect()
from a scope that has a Dispatcher.UI type. Will the flow chain process in this UI scope by default? Am I forced to use
flowOn(IOContext)
to make it execute off the UI thread?
s
@Pablichjenkov That is not necessary a problem. As long as you don’t have blocking code in your Flow, you should be all set. If you have suspending code inside your Flow, that is not a problem either, since suspending won’t block the UI thread
p
Well by flow chain process I mean flows that have suspending functions inside and either IO or heavy computation blocks. Where these suspending blocks will be executed if not passed any Dispatcher explicitly, Dispatcher.Default?
l
All the info about that is already in kotlinx.coroutines docs. You can verify what you see in the docs, that should help you understand what to expect.
o
flows run on the same dispatcher as whatever calls the terminal operations, unless you use
flowOn
, then everything setup before that call runs in the context passed there (calls after
flowOn
still use the same dispatcher as the terminal op caller)
p
@octylFractal I read what you just said, however, my concern was about the following: You have 2 types of code in a flow, lets say.
Copy code
// case 1
flow {

    suspendingBlockingFunc()

}
//and case 2
flow {

    nonSuspendingBlockingFunc() // Blocks either by IO or heavy CPU

}
If not using
flowOn
operator and calling
collect()
from Dispatcher.UI. Case 1 flow will execute on UI killing it Case 2 flow will execute on where? -> Default?
o
exactly what I said, the same dispatcher as
collect()
that is, case 1 & 2 are the same, there is no difference in how they are executed besides what the function they call does
p
I see it now. There is no magic behind it.
thnks