Android Kotlin基礎講座 06.2: コルーチンとRoom

概念:コルーチン

メインスレッドのブロッキング無しにロングランニングタスクを行わせるためのパターンの一つがコールバックを使うことです。マルチスレッドとコールバックについてのイントロダクションを見たい方はMulti-threading & callbacks primer(英文)をご覧ください。

Kotlinにおいて、コルーチンとはロングランニングタスクをエレガントかつ効率的に扱うための方法です。Kotlinコルーチンはコールバックベースのコードをシーケンシャル(一連の)コードに変換してくれます。シーケンシャルに書かれたコードは一般的に可読性が高く、例外のような言語ごとの特徴を使うこともできます。最終的にはコルーチンとコールバックは同じことをします。つまりロングランニングタスクとから結果が手に入るの待ってから処理を続行します。

コルーチンには以下の性質があります。

  • コルーチンは非同期でノンブロッキングです。
  • コルーチンは非同期なコードをシーケンシャルにするために、suspend関数を使います。

コルーチンは非同期

コルーチンはプログラムのメイン処理から独立して実行されます。これは平行して、または別のプロセッサで行われることがあります。またアプリがインプットを待っている間に別の処理を行っているといった場合もあります。非同期の重要な点は、明示的に待機するまで、結果が入手できないということです。

例えば、今あなたには調査を必要とする質問があり、答えを知るために同僚に尋ねたとしましょう。彼らは答えを知るために調査に行き、それについて調べます。これは”非同期”かつ”別のスレッド”で行われていることに似ています。あなた自身は同僚が答えを教えに戻ってくるまでに、質問の答えに関係のない別の仕事をし続けることができます。

コルーチンはノンブロッキング

ノンブロッキングとはコルーチンがメインスレッドまたはUIスレッドをブロックしないということを意味します。ですので、コルーチンを用いることで、ユーザーは快適にアプリを操作することができます。UIの応答が常に優先されるためです。

コルーチンは非同期なコードをシーケンシャルにするために、suspend関数を使う

suspendというキーワードは、コルーチンで使えるようにするために関数または関数のタイプをマーキングするKotlinの手法です。コルーチンがsuspendでマーキングされた関数を呼び出す際、通常の関数のように結果を返すまでブロッキングする代わりに、コルーチンは結果の準備ができるまで実行を停止します。それからコルーチンは中断したところから再開し、結果を返します。

コルーチンが一時停止し結果を待っている間、それが実行されているスレッドをブロックしません。そうすることで、他の関数やコルーチンが実行されることを可能にしています。

supendキーワードはコードが実行されるスレッドを指定しません。suspend関数はバックグラウンドスレッド、またはメインスレッド上で実行されます。

Tip: ブロッキングと一時停止の違いは、スレッドがブロックされている場合、他の処理は行われないのに対して、スレッドが一時停止されている場合、他の処理は結果が利用可能になるまで行われるということです。

Kotlinでコルーチンを利用するためには、以下の三つが必要です。

  • ジョブ
  • ディスパッチャー
  • スコープ

ジョブ: 基本的にジョブとはキャンセルされ得るもの全てです。全てのコルーチンにはジョブがあり、コルーチンをキャンセルするためにジョブを使うことができます。ジョブは親子ヒエラルキーになっていることもあります。
親ジョブをキャンセルすることは同時に全ての子ジョブもキャンセルします。手動でそれぞれのコルーチンをキャンセルするよりもかなり便利です。

ディスパッチャー:ディスパッチャーは様々なスレッドで実行するためにコルーチンを送信します。例えば、Dispatcher.Mainはメインスレッドでタスクを実行させ、Dispatcher.IOはブロッキングI/Oタスクをスレッドの共有プールにオフロードします。

スコープ:コルーチンのスコープはコルーチンが実行されているコンテクストを定義します。スコープはコルーチンのジョブとディスパッチャーに関する情報を組み合わせます。スコープはコルーチンを追跡します。コルーチンを開始した際、それは”スコープ内”にあり、これはどのスコープがコルーチンを追跡するかを指定したことを意味します。

アーキテクチャコンポーネントを用いたKotlinコルーチン

CoroutineScope: CroutineScopeは全てのコルーチンを追跡し、いつコルーチンが実行されるべきかを管理するのに役立ちます。またその中で開始された全てのコルーチンをキャンセルすることもできます。それぞれの非同期処理またはコルーチンは特定のスコープ内で行われます。

アーキテクチャコンポーネントはアプリにおける論理的なスコープ用コルーチンのサポートを提供してくれています。アーキテクチャコンポーネントは、アプリで利用できる以下の組み込みスコープを低gしています。組み込みコルーチンスコープはそれぞれの対応するアーキテクチャコンポーネント用のKTX extensionsの中にあります。これらのスコープを使う際は適切な依存関係を追加することを忘れないでください。

ViewModelScope: ViewModelScopeはアプリのそれぞれのViewModel用に定義されています。このスコープ内のどのコルーチンもViewModelがクリアされると自動でキャンセルされます。この記事ではデータベース操作を初期化するためにViewModelScopeを使います。

Roomとディスパッチャー

データベース操作をするためにRoomライブラリを使う際、RoomはDispatcher.IOを使ってバックグラウンドでのデータベース操作を行います。あなた自身が明示的にDispatcherを指定する必要はありません。