Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Explanation of intriguing behavior of coroutines

I have a method that runs some operations in a row. Is is actually a for loop, which loops it’s contents 50 times, each iteration taking roughly 0.2 seconds. I have a constant animation being presented on the screen for the duration of this execution. So, it is obvious that I wish to carry these operations off the main thread, so my animation can keep up (or the recompositions can take place, this is Compose). What I realized is, that this simple method

fun run(){
        repeat(10000) {
            repeat(5000){
                print("I ♥ Kotlin")
            }
        }
    }

if run in a standard Composable scope just like that, will block the UI thread as one would expect.

b) it would also block the UI thread if I call it in a LaunchedEffect while nesting it in a call to launch{...}.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

c) It does not block if I run it on an I/O coroutine, which is also the default coroutine.

d) the app sometimes crashes if run on the Main Dispatcher

Now, simple question – why is this?

LaunchedEffect(Unit){
 run() // Block
}
Launchedeffect(Unit){
 launch{
  run() // Block
 }
}
LaunchedEffect(Unit){
 withContext(Dispatchers.Main){
  run() //Blocks, and at times, crashes
 }
}
LaunchedEffect(Unit){
 withContext(Dispatchers.IO){
  run() // Runs without blocking
 }
}
thread{
 run() //Runs without blocking, no crash
}

Can anyone explain why the Dispatchers.IO works and the others don’t? It’s sort of giving me undesired stress.

If anyone requires a quick animation UI to test it out, here it is

@Composable
fun DUM_E_MARK_II() {

    val sizeTransition = rememberInfiniteTransition()

    val size by sizeTransition.animateFloat(
        initialValue = 50f,
        targetValue = 200f,
        animationSpec = infiniteRepeatable(
            keyframes { durationMillis = 1000 },
            repeatMode = RepeatMode.Reverse,
        )
    )

    Icon(
        imageVector = Icons.Filled.Warning,
        contentDescription = "",
        modifier = Modifier.size(size.dp),
        tint = Color.Red
    )

}

>Solution :

Your code is a long-running, non-suspendable task. It blocks whatever thread it runs on for its entire lifetime. When you block the UI thread, it causes the UI to freeze, and after a timeout Android kills such a misbehaving application.

If you use any dispatcher that uses its own thread pool, for example IO, the task will block a non-UI thread.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading