Kotlin协程吞下异常

Kotlin coroutine swallows exception

我对异常处理如何与协程一起工作感到非常困惑。

我希望可以有一个挂起函数链,它们可以像同步代码一样在它们之间传递异常。因此,如果说 Retrofit 抛出 IOException,我可以在挂起函数链的开头处理该异常,例如在演示者中向用户显示错误。

我做了这个简单的例子来尝试协程,但是如果我取消注释 throw Exception 在异常失败后调用代码 运行 但异常不会使应用程序崩溃。

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()
    }
}

我试过使用 asyncCoroutineExceptionHandler

使用 async 时,您应该 await 某处的结果,这样您就不会丢失任何异常。

这是根据 Alexey Romanov 的回答捕获异常的代码。通过更多的工作,我已经开始使用它了。添加 Log.d("thread", Thread.currentThread().name) 表明延迟未阻塞 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()
    }
}