since coroutine scope is used in almost all screen...
# compose
m
since coroutine scope is used in almost all screens, and to avoid passing it around. does it make sense to provide it via compositionLocal in the theme ?
c
No, use
rememberCoroutineScope()
to access the scope of a particular Composable, or else bubble events up to a ViewModel to handle in the
viewModelScope
m
hm. in that case. Do we need a scope for every distinct composable that needs it, for instance: snackbar, pager, dialog, bottomSheet. Or can we use the same scope. I’m currently using only 1 scope and it works fine. What is the best practice ?
a
Depends on your usecase, if you want to cancel your coroutine job after the composable is removed from the tree then you should use rememberCouroitineScope inside that composable. If you don't want to cancel the job then you should pass the CoroutineScope from parent composable If later is your usecase and your passing that scope to multiple functions then you can use CompositionLocal. One case is you don't want to cancel an API (assume sendFriendRequest api) when user clicks back button
m
ya. For things like snackbar, pagers, bottomSheets, dialogs, etc. Do you use the same parent scope, or create new ones per composable?
c
Yeah, it kinda depends on the use-case. But generally, I would say it could get confusing to pass a coroutineScope around with Locals, since you can also get a coroutineScope from
rememberCoroutineScope()
. If you want the coroutine to be bound to a particular UI composable, use the most local
rememberCoroutineScope()
you can (i.e. access it from the body of the function and don't pass it to children functions). If you want a coroutineScope that persists beyond any single Composable, then it shouldn't really be touched directly by child composables. Instead, the child composables should "bubble up" an "event" (callbacks) to the point that holds the scope, to avoid coupling a Composable to a coroutineScope that it is not directly tied to. This could be a
rememberCoroutineScope
somewhere higher up the UI tree, or bubbled all the way to the screen root and passed to a ViewModel
☝️ 1
m
ok. thanks for the info!
c
Note that none of those APIs themselves have anything to do with coroutines or scopes. The state itself, like everything in Compose, is entirely immutable. It's really just the animations that need to be updated with a suspending API. So the coroutine scopes for those should be related to where the animations are running, to ensure they run to completion. For example, see that in this article the coroutine scope is created at the same point that the BottomSheetScaffoldState itself is https://proandroiddev.com/bottom-sheet-in-jetpack-compose-c8ab7a297aac So children composables should not call the APIs for those states directly, or even have access to those state objects, but be more passive and just offer callback functions to pass data up through the tree to the root where those state objects are created and managed.
And if you've got all those state objects for snackbar, bottom sheet, etc. all created in the same place, you can use the same instance of
rememberCoroutineScope
for all of them, each
launch { }
will run in parallel to the others
And when I talked about "bubbling up events", these articles in the docs describe better what I meant: • https://developer.android.com/jetpack/compose/state#state-hoistinghttps://developer.android.com/jetpack/compose/mental-model
m
yes, that part i got it. thanks