2017-12-12 3 views
1

Ich bin sehr verwirrt darüber, wie Exception-Behandlung mit Korotinen funktioniert.Kotlin Coroutine schluckt Ausnahme

Ich hatte gehofft, dass es möglich wäre, eine Kette von Aussetzungsfunktionen zu haben, die Ausnahmen wie synchronen Code zwischen sich übergeben würden. Wenn Retrofit beispielsweise eine IOException ausgelöst hat, könnte ich diese Ausnahme am Anfang der Kette von Suspend-Funktionen behandeln, beispielsweise in einem Presenter, um einem Benutzer einen Fehler anzuzeigen.

Ich machte dieses einfache Beispiel, um Korotinen auszuprobieren, aber wenn ich throw Exception auskommentieren Sie den Code, nachdem die Ausnahme fehlschlägt, aber die Ausnahme stürzt die App nicht ab.

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

Ich habe versucht, async und CoroutineExceptionHandler verwenden.

Antwort

1

Wenn Sie async verwenden, sollten Sie das Ergebnis await irgendwo, damit Sie keine Ausnahmen verlieren.

+0

ich versucht hatte, 'async' mit' await' vor, aber es beschwert sich, dass 'Funktion Suspend await sollte nur von einem Koroutine aufgerufen werden oder eine andere aussetzen function.' jedoch alles in Einwickeln' runBlocking' arbeitet ohne Unterbrechung das asynchrone Ausführen des Codes. 'runBlocking' ist ein verwirrender Name, da ich erwartet habe, dass er blockiert, bis die Koroutinen abgeschlossen sind. In meinem Fall bedeutet das, dass wenn Sie schnell auf den Button geklickt haben, ich erwartet habe, dass Sie die Zahl in Sekunden statt schnell erhöhen würde. Ich werde dies als Antwort markieren, aber meinen festen Code in eine andere Antwort setzen. – TTransmit

+0

Wenn ich genauer hinschaue, kann ich sehen, dass 'runBlocking' in diesem Fall den UI-Thread blockiert, was ich nicht möchte. Ich muss versuchen, einen Rückruf zu verwenden. – TTransmit

+0

Die Verwendung der Kotlinx 'Continuation' hier gibt mir bisher nur hässliche Callback-Hölle. – TTransmit

0

Hier ist Code, der die Ausnahme basierend auf Alexey Romanovs Antwort abfängt. Mit ein bisschen mehr Arbeit habe ich es mit dem Start arbeiten. Das Hinzufügen von Log.d("thread", Thread.currentThread().name) zeigt, dass die Verzögerungen UI nicht blockieren.

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([email protected], 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() 
    } 
}