I read the blog post by @elizarov on the shift to Structured concurrency and it was a bit… woosh. (which is fine, I’m not the target audience)
I never fully understood why launch(UI) { ... }
was good, bad, or even necessary, and to be honest, I don’t want to know - I want things to work without crashing, it is ok if I don’t get how the underlying system handles it.
So I went ahead and accepted the IDE’s suggestions, and ended up with calls like GlobalScope.launch(Dispatchers.Main) { …do stuff… }
… is this good? Do I like GlobalScope? Do I like Dispatchers.Main? (and do they like me back enough not to throw random errors like when I used launch(UI)
incorrectly?) Because it is in an Android activity, should I even be using any of that and would a launch { ... }
be better?
And if you know the answer to those, I’m betting you know the answer to “is this a sane way to do lazy suspend?”
Yours in accepting “accept suggestion” when the IDE says to
-Benjamin
Check out the updated coroutine UI documentation on “Structured concurrency, lifecycle and coroutine parent-child hierarchy”. Your Activity should implement the new CoroutineScope interface. Then you can launch a coroutine on the UI thread with launch { }
, and it will automatically be cancelled when the Activity is destroyed.
Oh! huh!
Well, I made my own ScopedAppActivity copying the example, and it seems to work… so… yay?
And today with new releases, it now says I’m doing it all wrong. I think I should stick with 1.2 until things settle.
I ran into an oddity:
val deferred = (1..maxAttempts).map { attemptNum -> async { ...do stuff
stopped using up all cores, seemed to be constrained to 100% cpu. (which is only 1 of my 8 cores)
Adding in async(Dispatchers.Default) {
to the async call started running everything in parallel again, correctly using 700% cpu (7 of 8 cores)
So, did you solve the problem?
Yes, but it felt funny implementing “CoroutineScope” and manually putting in the lines below. I was hoping for more “it just works!” parallel magic. But once I had this, all the sub-classes could use launch {...
without issue.
abstract class ScopedActivity : AppCompatActivity(), CoroutineScope {
private lateinit var job: Job
override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Main
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
job = Job()
}
override fun onDestroy() {
super.onDestroy()
job.cancel()
}
}
And in another project, I did not get it to work, and instead ripped out everything Kotlin Sequence/Actor/Coroutine/Channel and went back to plain java threads + Blocking Queue. Which makes me sad because I feel like it would be easier with Kotlin if I knew how to make it work.