问题
I'm very confused about how Exception handling works with coroutines.
I was hoping that it would be possible to have a chain of suspend functions that would pass Exceptions between themselves like synchronous code. So if say Retrofit threw an IOException, I could handle that exception at the beginning of the chain of suspend functions such as in a presenter to show an error to a user.
I made this simple example to try out coroutines but if I uncomment either throw Exception
call the code after the Exception fails to run but the Exception does not crash the app.
package com.example.myapplication
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.widget.Button
import android.widget.TextView
import kotlinx.coroutines.experimental.delay
import kotlinx.coroutines.experimental.launch
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val text = findViewById<TextView>(R.id.thing_text)
val button = findViewById<Button>(R.id.thing_button)
var count = 0
button.setOnClickListener {
launch {
count++
// throw Exception("Boom")
val string = delayedStringOfInt(count)
runOnUiThread { text.text = string }
}
}
}
suspend fun delayedStringOfInt(int: Int): String {
delay(1000)
// throw Exception("Boom")
return int.toString()
}
}
I have tried using async
and CoroutineExceptionHandler
.
回答1:
When using async
, you should await
the result somewhere so you don't lose any exceptions.
回答2:
Here is code that catches the exception based on Alexey Romanov's answer. With a bit more work I've got it working with launch. Adding Log.d("thread", Thread.currentThread().name)
shows that the delays are not blocking UI.
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val text = findViewById<TextView>(R.id.thing_text)
val button = findViewById<Button>(R.id.thing_button)
var count = 0
button.setOnClickListener {
launch {
val job = async {
count++
val string = delayedStringOfInt(count)
updateTextView(text, string)
}
try {
job.await()
} catch (e: IOException) {
makeToastFromException(e)
}
}
}
}
fun makeToastFromException(e: Exception) {
runOnUiThread {
Toast.makeText(this@MainActivity, e.localizedMessage, Toast.LENGTH_SHORT).show()
}
}
fun updateTextView(text: TextView, string: String) {
runOnUiThread { text.text = string }
}
suspend fun delayedStringOfInt(int: Int): String {
delay(2000)
if (int % 4 == 0) throw IOException("Boom")
return int.toString()
}
}
来源:https://stackoverflow.com/questions/47783141/kotlin-coroutine-swallows-exception