Ernie Thomason
Ernie Thomason

Reputation: 1709

Kotlin coroutine: how switch to UI thread and wait for callback

Process is on a background thread (async)

I want to open up a message box so user can tap Yes or No

After user taps Yes or No, a callback is performed (with result), then I want to continue the background async process.

I'm not sure how to do this.

I use suspendCoroutine to convert a callback function to something I can await. But suspendCourtine is running on background thread, not UI thread.

Calling something like withContext(Dispatchers.Main) inside suspendCoroutine doesn't compile.

// async function called from background thread
// I want the function to return AFTER user taps Yes or No

suspend fun showPopupYesNoAsync(title: String) : Boolean  {
    return suspendCoroutine { continuation ->
        // Problem is that here I'm on background thread and I can't open UI popup view
        openPopupYesNo(title= title) { tappedButton ->
            continuation.resume(tappedButton.id == "Yes")
        }
    }
}

Upvotes: 0

Views: 1093

Answers (2)

broot
broot

Reputation: 28362

You were close, but you should do the opposite of what you tried - put suspendCoroutine() inside withContext():

suspend fun showPopupYesNoAsync(title: String) : Boolean  {
    return withContext(Dispatchers.Main) {
        suspendCoroutine { continuation ->
            openPopupYesNo(title= title) { tappedButton ->
                continuation.resume(tappedButton.id == "Yes")
            }
        }
    }
}

Upvotes: 2

Sohaib Ahmed
Sohaib Ahmed

Reputation: 3062

If your process is on Background thread, we can assume

CoroutineScope(Dispatchers.Main).launch {
    val job = CoroutineScope(Dispatchers.IO).async {
        //Some process
        MaterialAlertDialogBuilder(globalContext)
            .setTitle("Title")
            .setMessage("This is a message")
            .setPositiveButton("Yes") { dialog, which ->
                proceedWorking()
            }
            .setNegativeButton("No") { dialog, which -> dialog.dismiss() }
            .show()
    }
    job.await()
}

Invoke another method either suspend or another coroutine to continue your task as follow:

private fun proceedWorking() = CoroutineScope(Dispatchers.IO).launch {
    // Your new process after confirmation
}

Upvotes: 2

Related Questions