Kotlinのコルーチンは、OSスレッドをブロックせずに計算を一時停止および再開できる軽量スレッドです。launchやasyncなどの関数を通じて、親のCoroutineScopeがある場合に起動されます。
ディスパッチは、コルーチンが実行されるスレッドまたはエグゼキュータを決定するCoroutineDispatcherオブジェクトを介して行われます(Dispatchers.Main、Dispatchers.IO、Dispatchers.Default など)。
例:
fun main() = runBlocking { launch(Dispatchers.IO) { val data = getDataFromNetwork() withContext(Dispatchers.Main) { updateUI(data) } } }
キャンセル: コルーチンは、ジョブ/スコープのキャンセルを通じてキャンセルされ、その際に内部の例外CancellationExceptionがスローされます。コルーチンは定期的にキャンセルフラグを確認するか、正常に終了するために一時停止する関数を呼び出す必要があります。
エラーハンドリング: コルーチン内の例外は「沈む」ことがあり、子コルーチン内のエラーを処理しなければ、子コルーチンは終了するだけで、親は問題を認識しません。これに対処するために、SupervisorJobとCoroutineExceptionHandlerのメカニズムがあります。
コンテキストの伝達に関するニュアンス:
親コルーチン内の子コルーチンの1つがエラーで終了し、他の子コルーチンが動作し続けるとどうなりますか?すべての子コルーチンはキャンセルされますか?
多くの人が「エラーは子に残る」と誤解しています。
正しい答え: 通常のジョブ(またはlaunch)を使用している場合、いずれかの子コルーチンでエラーが発生すると、すべての子コルーチンが自動的にキャンセルされます。子コルーチンのキャンセルを防ぐためには、SupervisorJobまたはsupervisorScopeを使用します:
supervisorScope { launch { error("fail") } launch { println("このコードは動作します") } }
物語
エラー処理の不適切な処理 - フローのクラッシュ : プロジェクトではデータを取得するためにコルーチンが使用されていました。例外は子コルーチン内で「沈み」、リトライ/リカバリーのレベルが機能せず、メイン画面は空のままで、ユーザーにエラーメッセージが表示されませんでした。
物語
Dispatchers.Mainでの作業によるUIのフリーズ : 若いAndroid開発者は、Dispatchers.Mainで重い計算タスクを実行し、UIが「フリーズ」しました。重い計算はDispatchers.DefaultまたはDispatchers.IOで実行する必要があるという理解が欠けていました。
物語
親スコープのキャンセルによるAbortError : 開発者の1人は、親スコープがキャンセルされた場合、すべての子コルーチンがキャンセルされることを考慮せず、重要な操作(データ保存)が完了しませんでした。