Я пытаюсь понять обработку исключений в сопрограммах Kotlin, поэтому я придумал этот очень простой сценарий, когда сетевой вызов выдает исключение, и мое приложение должно его перехватить и обработать.
Если яокружить мой вызов async.await () блоком try-catch, он работает как задумано. Тем не менее, если я пытаюсь абстрагировать этот try-catch в функцию расширения, мое приложение вылетает.
Что мне здесь не хватает?
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import kotlinx.coroutines.*
class Main2Activity : AppCompatActivity() {
private val job: Job = Job()
private val scope = CoroutineScope(Dispatchers.Default + job)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main2)
runCode()
}
private suspend fun asyncCallThrowsException(): Deferred<Boolean> =
withContext(Dispatchers.IO) {
Thread.sleep(3000)// simulates a blocking request/response (not on the Main thread, though)
throw(Exception())
}
suspend fun <T> Deferred<T>.awaitAndCatch() {
try {
this.await()
} catch (e: Exception) {
println("exception caught inside awaitAndCatch")
}
}
private fun runCode() {
scope.launch {
//This block catches the exception.
try {
val resultDeferred = asyncCallThrowsException()
resultDeferred.await()
} catch (e: Exception) {
println("exception caught inside try-catch")
}
//This line does not, and crashes my app.
asyncCallThrowsException().awaitAndCatch()
}
}
}
Редактировать: Iна самом деле забыл обернуть вызов внутри блока async
. Теперь даже не работает явный блок try-catch ...
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import kotlinx.coroutines.*
class Main4Activity : AppCompatActivity() {
private val job: Job = Job()
private val scope = CoroutineScope(Dispatchers.Default + job)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
runCode()
}
private suspend fun callThrowsException(): String =
withContext(Dispatchers.IO) {
Thread.sleep(3000)// simulates a blocking request/response (not on the Main thread, though)
throw(Exception())
"my result"
}
suspend fun <T> Deferred<T>.awaitAndCatch(): T? {
try {
return this.await()
} catch (e: Exception) {
println("exception caught inside awaitAndCatch")
}
return null
}
private fun runCode() {
scope.launch {
val resultDeferred: Deferred<String> = async { callThrowsException() }
var result: String?
// This doesn't catch the throwable, and my app crashes - but the message gets printed to the console.
try {
result = resultDeferred.await()
} catch (e: Exception) {
println("exception caught inside try-catch")
}
// This doesn't catch the throwable, and my app crashes - but the message gets printed to the console.
result = resultDeferred.awaitAndCatch()
}
}
}