Daniel Oliveira
Daniel Oliveira

Reputation: 8993

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 ?

Upvotes: 4

Views: 2278

Answers (1)

Marko Topolnik
Marko Topolnik

Reputation: 200246

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.

Upvotes: 13

Related Questions