Common usage of CoroutineScope Job functions are difficult to understand
See original GitHub issueOne problem we have on our team when onboarding developers to Coroutines is the complex access to the Job
in a CoroutineScope
- specifically scope.coroutineContext[Job]!!
. Access to methods like .invokeOnCompletion
, cancel
, etc are unwieldy to use because of the Job
nullability and violation of the Law of Demeter.
// easy to use/understand
scope.invokeOnCompletion { }
scope.cancel { }
// difficult to understand
scope.coroutineContext[Job]!!.invokeOnCompletion { }
scope.coroutineContext[Job]!!..cancel { }
The latter is more difficult because you have to understand that a CoroutineScope
is just a wrapper around a CoroutineContext
that will always have a Job
(even though the API says a Job
can be null
). And once it is undestood, it’s a pretty verbose API.
Possible Solutions
I see two possible solutions going forward (though both could be implemented).
- Put commonly used functions like
.cancel()
,invokeOnCompletion{ }
, etc as extension functions onCoroutineScope
. - Add an extension function
scope.job
that returns an non-nullJob
- because aJob
should never be null for aCoroutineScope
.
note: scope.cancel()
was added in https://github.com/Kotlin/kotlinx.coroutines/pull/866
Issue Analytics
- State:
- Created 5 years ago
- Reactions:6
- Comments:9 (5 by maintainers)
Top Results From Across the Web
Coroutine scope functions - Kt. Academy
The first approach is calling suspending functions from a suspending function. The problem with this solution is that it is not concurrent ...
Read more >Best practices for coroutines in Android
This page presents several best practices that have a positive impact by making your app more scalable and testable when using coroutines.
Read more >7 common mistakes you might be making when using Kotlin ...
Common Mistake #1: Instantiating a new job instance when launching a Coroutine. Sometimes you need a job as a handle to your Coroutine...
Read more >How to make sense of Kotlin coroutines | by Joffrey Bion
The coroutineScope builder. You may have noticed that the use of runBlocking is discouraged from inside coroutines. This is because the Kotlin ...
Read more >Coroutines & Patterns for work that shouldn't be cancelled
On Android, you can use the CoroutineScope s provided by Jetpack: viewModelScope or lifecycleScope that cancel any running work when their ...
Read more >
Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free
Top Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
We are using:
I’m currently using it to signal a
ViewModel.onCleared()
event, instead of relying on extending the android arch componentsViewModel
Ultimately, I think it’s important to understand that the handle on coroutines created from a
CoroutineScope
is aJob
. Is it safe to assume that allCoroutineScope
instances should have aJob
associated with this?I don’t think it’s very important (for beginners) to understand that a
Job
lives inside aCoroutineContext
. In most common usage - the interesting bits of using aCoroutineScope
are what dispatcher is used, and being able to control the scope’s lifecycle viaJob
. I think this is an argument in favor of a standalone.job
extension.The above is simple to onboard beginner devs to. The following is not:
It requires a dev to understand that:
Job
is a special part of aCoroutineContext
Job.Companion
as aKey<Job>
for accessing theJob
instance of aCoroutineContext
Job
should never benull
in aCoroutineScope
, so it is safe to force unwrap it (!!
)Job
will automatically be created for you if you don’t specify itNot requiring a dev to understand those things at the very beginning for the very basics would be a big win
I’d use this opportunity to take a better look at
Job
use-cases and cover the missing ones withCoroutineScope
. I see two main missing pieces that require aJob
here:cancelChildren()
– this is easy to add. The only problem with it is that, in general, this function is extremely hard to use right in a race-free manner. Can you elaborate what are use-cases for this particular function?invokeOnCancellation { ... }
– this is quite an advanced low-level function, because, for one thing, it does not specify which context it is invoked in, so it is easy to use incorrectly in a non-thread-safe manner. Can you give a bit more of example of how you use it, please. We might be able to design a safer alternative that would be a better fit forCoroutineScope
extension.