Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Providing Dispatches.Main for runBlocking hang the Android App. Why?

When I'm running the code below in Android, it runs fine.

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        runBlocking {
            launch { 
                Log.d("Track", "main runBlocking pre       : ${Thread.currentThread().name}")
                delay(500)
                Log.d("Track", "main runBlocking post      : ${Thread.currentThread().name}")
            }
        }
    }

It print

Track: main runBlocking pre       : main
Track: main runBlocking post      : main

However, if I provide the Main context to runBlocking, as I have below

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        runBlocking(Dispatchers.Main) { // Provide Dispatchers.Main
            launch { 
                Log.d("Track", "main runBlocking pre       : ${Thread.currentThread().name}")
                delay(500)
                Log.d("Track", "main runBlocking post      : ${Thread.currentThread().name}")
            }
        }
    }

it hangs and not running it.

Note: the Dispatchers.Main is using

implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.1'

Why did it hang?

I thought not providing Dispatchers.Main to the runBlocking is to have it run in main thread, which is the same as providing Dispatchers.Main. Did I mis-understand it?

Note: The libraries I use are as below

    implementation "org.jetbrains.kotlin:kotlin-stdlib:1.4.21"
    implementation 'androidx.core:core-ktx:1.3.2'
    implementation 'androidx.appcompat:appcompat:1.2.0'
    implementation 'com.google.android.material:material:1.2.1'
    implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.2'
    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.1'
    testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.4.2'
like image 807
Elye Avatar asked Dec 25 '20 10:12

Elye


1 Answers

runBlocking's default dispatcher is a custom dispatcher that uses the thread it was called on to run the continuations of the coroutine. This is why when you log from within the runBlocking coroutine block, it reports that it is on the main thread.

However, this is different that running something on Dispatchers.Main. Dispatchers.Main literally handles coroutine continuations by posting code blocks as runnables to the main Handler. However, that handler is currently running this onCreate method, and won't be able to handle other messages in its queue until onCreate returns. But runBlocking won't return until its child coroutines return, so onCreate can never return.

The default runBlocking dispatcher on the other hand runs the continuations directly on the current thread before it even returns. It doesn't even know about Handlers. If you launch a coroutine into Dispatchers.main from within runBlocking with its default dispatcher, I think you'll have the same kind of hang.

like image 97
Tenfour04 Avatar answered Oct 21 '22 14:10

Tenfour04