Hey everyone :wave: how do you usually create cor...
# coroutines
t
Hey everyone 👋 how do you usually create coroutines when you need to do work outside of a view scope. Let's say you have a VM that inserts an update into a database when the user closes the screen. Manu suggested in his article to use a singleton scope for the entire app lifetime like
val applicationScope = CoroutineScope(SupervisorJob() + otherConfig)
.
No matter if using a DI framework or access the scope via the application object, I wonder why it is recommended to be a SINGLETON? Whenever someone calls
applicationScope.cancel()
, the scope is dead and new coroutines can't be launched anymore. Meaning
applicationScope.launch()
would not work anymore. This can lead to hard to debug bugs Wouldn't it be better to inject newly created scopes each time I need a scope that lives longer than the VM? In the particular case of the article instead of
val applicationScope = CoroutineScope(SupervisorJob() + otherConfig)
make it a function that returns a new instance. Or using
Factory
instead of
Single
in the case of Koin Happy to hear your thoughts about that topic
r
Why would
applicationScope.cancel()
be called any time other than when the application is shutting down? And then if the application has been shut down, how are new coroutines being launched?
âž• 1
t
In cases in which someone calls
applicationScope.cancel()
without anyone noticing. Cases like this can happen (e.g. bigger teams, unexperienced devs,...) • And then if the application has been shut down, how are new coroutines being launched? Not sure if I understand that question. When the application is shut down all the coroutines are cancelled. If it is launched again the coroutines are gone and would not continue running. You don't have access to them anymore
r
I'd bet the above article author is not accounting for your scenario of "someone goofed and
applicationScope
got cancelled when it shouldn't have been" because there are more than a million ways you can always goof something up; I don't think it's the author's job to account for them all. Rather, they're setting forth a solution. I think the assumption is "if you have bugs preventing this from working correctly, you'll fix those bugs". (My second question was rhetorical, trying to highlight that you shouldn't ever have both a canceled
applicationScope
and more work to be done in that scope. Sorry for the lack of clarity) If you are worried about
applicationScope
being canceled when it shouldn't, then you certainly can try out some other solution such as a factory function to get you more transient scopes, but I don't know how that would affect performance, garbage collection, etc. But in general I think most people would prefer the singleton
applicationScope
solution since it avoids the overhead of creating unnecessary new scopes. I'd be satisfied with a comment on its declaration saying "don't cancel this until total app shutdown" or similar.
t
I only wanted to share the article for reference as it is linked in the docs from Google. It definitely serves it's purpose and should not take into account for edge cases or all bugs that could happen. I'd mostly be interested in opinions of others about this topic and what they think about using a singleton scope
k
You can also use the application scope + NonCancellable to emphasize what you are trying to achieve: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-non-cancellable/
💯 1
b
How bout create a component with a dedicated scope. I.e. object UnicornManager{ val scope=.... fun crateUnicorn(...) = scope.launch{....} fun delete(....) = scope.launch{....} } You can compile this component to its own module or move it around freely in any target module you need it. Writing a view scope for some views and imho a view model for some views is the worst idea ever. This is responsible for every broken app on the marketplace right now. Some people call it "stale view state holders" but i think inaccurately scoped state holders is more appropriate. How bout write a view model for each model not for each view/view group. or simply write your own scoped component. Again targeting a feature or a model in your app not some views. Ah consider putting in completion lambdas: fun createUnicorn( ..., onComplete: (Unicorn?) -> Unit // Changed to nullable Unicorn ) = scope.launch {... ApplicationScope or main scope is such a relative thing. I would totally write an applicationScope if i want to integrate the entire app in another app. As is, without the ui, headless mode. Like i do Playwright for java in other desktop apps. I write a component DevBrowser and i slam a scope and i have a isolated playwright shell i can move around. just like that. You cant make decisions for how to scope in a vacuum like that. It dont really matterif you are making only one component for one app. You are just going to chase your tail thinking how to scope. Scoping components matters much more if you plan to grab that component as is and move it over in some other app or module and it's supposed to just work!