Hi, the most important difference is, that launchIn actually launches collecting the flow. Without launchIn or collect code in your flow will not execute. flowOn is not collecting flow. It is only used to specify in which context the flow is executed.
This is most useful if you want to execute the flow on non UI thread, for example if the flow is computation heavy. If it's computation heavy and uses CPU too much, you don't want to execute it on the main thread, because despite the fact that it would use coroutines, the code would still have to be executed on the same CPU core as the UI, so that would slow down UI as well.
However, even if you want your flow to execute on the non UI thread, in most cases you want to display the result in UI. So the result of the flow actually has to be collected in the coroutine scope of the UI thread.
And for that you will specify the coroutine scope of the UI thread when calling launchIn (or you'd call collect in the appropriate coroutine launch block)