Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why this Kotlin Coroutine is freezing the interface?

So, I had this code running inside a "onBindViewHolder" recycler's adapter method:

 launch(UI) {
            val bitmapDrawable = loadLargeBitmapDrawable()          
            imageView.setImageDrawable(bitmapDrawable)
  }

This was freezing my app for some seconds, locking my mainthread.

But then I changed to this:

launch { // <- I removed the "UI"
            val bitmapDrawable = loadLargeBitmapDrawable()  

            launch(UI) { //Launch the UI coroutine inside the other
                imageView.setImageDrawable(bitmapDrawable)
            }      

  }

Why this is happening? The purpose of coroutines are to make things async inside the same thread (UI) right? Someone can explain me why I had to run a UI coroutine inside another coroutine scope ?

like image 323
Daniel Oliveira Avatar asked Dec 13 '22 18:12

Daniel Oliveira


1 Answers

The purpose of coroutines are to make things async inside the same thread (UI) right?

You ascribe more magic to coroutines than there really is. If your loadLargeBitmapDrawable() function is not suspendable, but simply occupies its thread until done, there is nothing Kotlin can do about it. When you said launch(UI), you ordered that function run on the UI thread.

Your second example executes in the CommonPool context (that's the default) and then posts a task to the UI thread; a more natural way to say it is like this (I use it in my code, with the exact same purpose as you):

launch(UI) {
    val bitmapDrawable = withContext(CommonPool) {
        loadLargeBitmapDrawable() 
    }
    imageView.setImageDrawable(bitmapDrawable)
}

withContext will suspend the coroutine you launched on the UI thread, submit the heavyweight operation to the common threadpool, and then resume the coroutine on the UI thread with its result. Now you can push the bitmap to the imageView.

like image 115
Marko Topolnik Avatar answered Dec 17 '22 23:12

Marko Topolnik