2017-12-12 13 views
1

コルーチンで例外処理がどのように機能するのか非常に混乱します。コトリンコルーチンが嚥下する例外

私は、同期コードのように例外を渡すサスペンド機能の連鎖を持つことができると考えていました。だから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を使用して試してみました。

答えて

1

asyncを使用している場合は、結果はどこかにあるawaitになりますので、例外を失うことはありません。

+0

私は前に 'await'と' async'をしようとしたが、それは '関数をサスペンドだけコルーチンや他から呼び出されるべきで待つことに文句を中断することなく、runBlocking'が働く'でそれをすべてを包む、ただしfunction.'を中断しますコードの非同期実行'runBlocking'は、内部のコルーチンが完了するまでブロックすることを期待していたので、混乱する名前です。私の場合、あなたが急にボタンをクリックした場合、急速ではなく毎秒増加する数字が得られると予想していました。私はこれを答えとしてマークしますが、固定コードを別の答えに入れます。 – TTransmit

+0

もっと見ると、 'runBlocking'がUIスレッドをブロックしているのがわかります。これは私が望むものではありません。私はコールバックを使用してみる必要があります。 – TTransmit

+0

ここでkotlinx 'Continuation'を使うと、今まで私に醜いコールバック地獄を与えているだけです。 – TTransmit

0

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