Android Studio のコルーチンの概要

コレクションでコンテンツを整理 必要に応じて、コンテンツの保存と分類を行います。

1. 始める前に

前の Codelab では、コルーチンについて学習しました。Kotlin プレイグラウンドを使用して、コルーチンで同時実行コードを記述しました。この Codelab では、Android アプリ内のコルーチンとそのライフサイクルに関する知識を利用します。新しいコルーチンを同時に起動するためのコードを追加し、それらのコルーチンをテストする方法を学習します。

前提条件

  • Kotlin 言語の基本(関数やラムダを含む)に関する知識
  • Jetpack Compose でレイアウトを作成できること
  • Kotlin で単体テストを作成できること(ViewModel Codelab の単体テストを作成するを参照)
  • スレッドと同時実行の仕組みに関する知識
  • コルーチンと CoroutineScope に関する基本的な知識

作成するアプリの概要

  • 2 人のプレーヤー間のレースの進行状況をシミュレートする Race Tracker アプリを作成します。このアプリを通して、コルーチンのさまざまな側面についてテストし、学習を深めることができます。

学習内容

  • Android アプリのライフサイクルにおけるコルーチンの使用。
  • 構造化された同時実行の原則。
  • コルーチンをテストする単体テストを作成する方法。

必要なもの

  • Android Studio の最新の安定版

2. アプリの概要

Race Tracker は、2 人のプレーヤーによる競走をシミュレートするアプリです。アプリ UI は、[Start / Pause] と [Reset] の 2 つのボタンと、ランナーの進行状況を示す 2 つの進行状況バーで構成されています。プレーヤー 1 と 2 は、それぞれ異なるスピードでレースを「走行」するように設定されています。レースが開始すると、プレーヤー 2 はプレーヤー 1 の 2 倍の速さで進みます。

アプリでコルーチンを使用して、次のことを確認します。

  • 両方のプレーヤーが同時に「競走」する。
  • アプリの UI がレスポンシブであり、レース中に進行状況バーが進む。

スターター コードには、Race Tracker アプリ用の UI コードが含まれています。Codelab のこのパートは主に、Android アプリ内の Kotlin コルーチンに慣れることに焦点を当てます。

スターター コードを取得する

まず、スターター コードをダウンロードします。

または、GitHub リポジトリのクローンを作成してコードを入手することもできます。

$ git clone https://github.com/google-developer-training/basic-android-kotlin-compose-training-race-tracker.git
$ cd basic-android-kotlin-compose-training-race-tracker
$ git checkout starter

スターター コードは Race Tracker GitHub リポジトリで確認できます。

スターター コードのチュートリアル

レースを始めるには、スタートボタンをクリックします。レースの最中には、スタートボタンのテキストが「一時停止」に変わります。

f82a5c59ba7db14c.png

このボタンを使用して、レースの一時停止と再開をいつでも行えます。

732b56f673003730.png

レースが開始すると、ステータス インジケーターを通じて各プレーヤーの進行状況を確認できます。コンポーズ可能な関数 StatusIndicator は、各プレーヤーの進行状況を表示します。この関数は LinearProgressIndicator コンポーザブルを使用して、進行状況バーを表示します。コルーチンを使用して進行状況の値を更新します。

43e387687b33d60.png

RaceParticipant: 進行状況を増やすためのデータを提供します。このクラスは、各プレーヤーの状態ホルダーであり、参加者の name、レースが完了するために必要な maxProgress、進行状況の増分間の遅延時間、レースの currentProgressinitialProgress を保持します。

次のセクションでは、コルーチンを使用して、アプリの UI をブロックせずにレースの進行状況をシミュレートする機能を実装します。

3. レースの進行状況を実装する

run() 関数を使用してプレーヤーの currentProgressmaxProgress と比較し、レースの全体的な進行状況を表示します。また、suspend 関数(delay())を使用して、進行状況の増分間にわずかな遅延を追加します。この関数は別の suspend 関数 delay() を呼び出しているため、suspend 関数である必要があります。また、この関数は、Codelab の後半でコルーチンから呼び出します。関数を実装する手順は次のとおりです。

  1. スターター コードの一部である RaceParticipant クラスを開きます。
  2. RaceParticipant クラス内で、run() という名前の新しい suspend 関数を定義します。
class RaceParticipant(
    ...
) {
    var currentProgress by mutableStateOf(initialProgress)
        private set

    suspend fun run() {

    }
    ...
}
  1. レースの進行状況をシミュレートするには、currentProgress が値 maxProgress100 に設定される)に達するまで実行される while ループを追加します。
class RaceParticipant(
    ...
    val maxProgress: Int = 100,
    ...
) {
    var currentProgress by mutableStateOf(initialProgress)
        private set

    suspend fun run() {
        while (currentProgress < maxProgress) {

        }
    }
    ...
}
  1. currentProgress の値は initialProgress0)に設定されています。参加者の進行状況をシミュレートするには、while ループ内で progressIncrement プロパティの値 currentProgress をインクリメントします。progressIncrement のデフォルト値は 1 です。
class RaceParticipant(
    ...
    val maxProgress: Int = 100,
    ...
    private val progressIncrement: Int = 1,
    private val initialProgress: Int = 0
) {
    ...
    var currentProgress by mutableStateOf(initialProgress)
        private set

    suspend fun run() {
        while (currentProgress < maxProgress) {
            currentProgress += progressIncrement
        }
    }
}
  1. レースのさまざまな進行状況間隔をシミュレートするには、delay() suspend 関数を使用します。progressDelayMillis プロパティの値を引数として渡します。
suspend fun run() {
    while (currentProgress < maxProgress) {
        delay(progressDelayMillis)
        currentProgress += progressIncrement
    }
}

今追加したコードを見ると、次のスクリーンショットのように、Android Studio の delay() 関数の呼び出しの左側にアイコンが表示されます。11b5df57dcb744dc.png

このアイコンは、関数が一時停止してから後で再開できる一次停止ポイントを示します。

次の図に示すように、コルーチンが遅延時間の完了を待っている間、メインスレッドはブロックされません。

a3c314fb082a9626.png

コルーチンは、目的の間隔値を指定して delay() 関数を呼び出した後、実行を一時停止します(ただし、ブロックしません)。遅延が完了すると、コルーチンは実行を再開し、currentProgress プロパティの値を更新します。

4. レースを開始する

ユーザーがスタートボタンを押すと、2 つのプレーヤー インスタンスそれぞれで suspend 関数 run() を呼び出して「レースを開始」します。そのためには、run() 関数を呼び出すコルーチンを起動します。

レースを開始するためのコルーチンを起動するときは、両方の参加者について次の点を確認する必要があります。

  • スタートボタンをクリックすると(コルーチンが起動すると)すぐに走行が開始します。
  • 一時停止ボタンまたはリセットボタンをクリックすると、それぞれ一時停止するか走行を停止します(コルーチンがキャンセルされます)。
  • ユーザーがアプリを閉じると、キャンセルが適切に処理されます。つまり、すべてのコルーチンがキャンセルされ、ライフサイクルにバインドされます。

レベル 1 の Codelab で、suspend 関数は別の suspend 関数からしか呼び出せないことを学習しました。コンポーザブル内から suspend 関数を安全に呼び出すには、LaunchedEffect() コンポーザブルを使用する必要があります。LaunchedEffect() コンポーザブルはコンポジションに残っている限り、指定された suspend 関数を実行します。コンポーズ可能な関数 LaunchedEffect() を使用すると、次のすべてを行うことができます。

  • LaunchedEffect() コンポーザブルを使用すると、コンポーザブルから suspend 関数を安全に呼び出すことができます。
  • LaunchedEffect() 関数は、Composition に入ると、コードブロックがパラメータとして渡されたコルーチンが起動されます。コンポジションに残っている限り、指定された suspend 関数を実行します。ユーザーが Race Tracker アプリのスタートボタンをクリックすると、LaunchedEffect() はコンポジションに入り、コルーチンを起動して進行状況を更新します。
  • LaunchedEffect() がコンポジションを出ると、コルーチンはキャンセルされます。アプリでユーザーがリセット / 一時停止ボタンをクリックすると、LaunchedEffect() がコンポジションから削除され、基となるコルーチンがキャンセルされます。

RaceTracker アプリの場合、ディスパッチャを明示的に提供する必要はありません(LaunchedEffect() によって処理されるため)。

レースを開始するには、参加者ごとに run() 関数を呼び出して、次の手順を行います。

  1. com.example.racetracker.ui パッケージ内の RaceTrackerApp.kt ファイルを開きます。
  2. RaceTrackerApp() コンポーザブルに移動し、raceInProgress の定義の後の行に LaunchedEffect() コンポーザブルの呼び出しを追加します。
@Composable
fun RaceTrackerApp() {
    ...
    var raceInProgress by remember { mutableStateOf(false) }

    LaunchedEffect {

    }
    RaceTrackerScreen(...)
}
  1. playerOne または playerTwo のインスタンスが別のインスタンスに置き換えられた場合、LaunchedEffect() は基となるコルーチンをキャンセルして再起動する必要があります。そのためには、playerOne オブジェクトと playerTwo オブジェクトを key として LaunchedEffect に追加します。テキスト値が変更されたときに Text() コンポーザブルを再コンポーズされる仕組みと同様に、LaunchedEffect() のいずれかの重要な引数が変更されると、基となるコルーチンがキャンセルされ、再起動されます。
LaunchedEffect(playerOne, playerTwo) {
}
  1. playerOne.run() 関数と playerTwo.run() 関数の呼び出しを追加します。
@Composable
fun RaceTrackerApp() {
    ...
    var raceInProgress by remember { mutableStateOf(false) }

    LaunchedEffect(playerOne, playerTwo) {
        playerOne.run()
        playerTwo.run()
    }
    RaceTrackerScreen(...)
}
  1. LaunchedEffect() ブロックを if 条件でラップします。この状態の初期値は false です。ユーザーがスタートボタンをクリックし、LaunchedEffect() が実行されると、raceInProgress 状態の値が true に更新されます。
if (raceInProgress) {
    LaunchedEffect(playerOne, playerTwo) {
        playerOne.run()
        playerTwo.run()
    }
}
  1. raceInProgress フラグを false に更新してレースを終了します。この値は、ユーザーが一時停止ボタンをクリックすると、false に設定されます。この値が false に設定されると、LaunchedEffect() により、起動されたすべてのコルーチンは確実にキャンセルされます。
LaunchedEffect(playerOne, playerTwo) {
    playerOne.run()
    playerTwo.run()
    raceInProgress = false
}
  1. アプリを実行し、スタートボタンをクリックします。プレーヤー 2 がレースを開始する前に、プレーヤー 1 がレースを完了していることがわかります。次の動画をご覧ください。

3f492eafa16ddae3.gif

公平なレースではないようです。次のセクションでは、同時実行タスクを起動して、両方のプレーヤーが同時に走行できるようにする方法、コンセプトを理解する方法、この動作を実装する方法を学習します。

5. 構造化された同時実行

コルーチンを使用してコードを記述する方法は、構造化された同時実行と呼ばれます。この種類のプログラミングにより、コードの読みやすさが改善し、開発時間が短縮します。構造化された同時実行とは、コルーチンに階層があるということです。つまり、タスクによってサブタスクが起動され、次いでサブタスクが起動されます。この階層の単位はコルーチン スコープと呼ばれます。コルーチン スコープは常にライフサイクルに関連付ける必要があります。

コルーチン API は、この構造化された同時実行に準拠した設計となっています。suspend としてマークされていない関数から suspend 関数を呼び出すことはできません。この制限により、launch などのコルーチン ビルダーから suspend 関数を確実に呼び出すことができます。これらのビルダーは、今度は CoroutineScope に関連付けられます。

6. 同時実行タスクを起動する

  1. 両方の参加者を同時に走行させるには、2 つのコルーチンを別々に起動し、run() 関数の各呼び出しをこれらのコルーチン内に移動します。playerOne.run() の呼び出しを launch ビルダーでラップします。
LaunchedEffect(playerOne, playerTwo) {
    launch { playerOne.run() }
    playerTwo.run()
    raceInProgress = false
}
  1. 同様に、playerTwo.run() 関数の呼び出しを launch ビルダーでラップします。この変更により、アプリは同時に実行される 2 つのコルーチンを起動します。両方のプレーヤーが同時に走行できるようになりました。
LaunchedEffect(playerOne, playerTwo) {
    launch { playerOne.run() }
    launch { playerTwo.run() }
    raceInProgress = false
}
  1. アプリを実行し、スタートボタンをクリックします。レースが開始される見込みでしたが、予想とは異なりボタンのテキストが「スタート」に戻ります。

68fce921638841c9.gif

両方のプレーヤーが走行を完了したら、Race Tracker アプリは [Pause] ボタンのテキストを [Start] にリセットする必要があります。ただしここでは、プレーヤーのレースの完了を待つのではなく、コルーチンが起動されるとすぐにアプリが raceInProgress を更新します。

LaunchedEffect(playerOne, playerTwo) {
    launch {playerOne.run() }
    launch {playerTwo.run() }
    raceInProgress = false // This will update the state immediately, without waiting for players to finish run() execution.
}

次の理由により、raceInProgress フラグがすぐに更新されます。

  • launch ビルダー関数は、playerOne.run() を実行するコルーチンを起動し、すぐにコードブロックの次の行を実行します。
  • playerTwo.run() 関数を実行する 2 番目の launch ビルダー関数でも、同じ実行フローが発生します。
  • 2 番目の launch ビルダーが返されると、すぐに raceInProgress フラグが更新されます。この場合、ボタンテキストはすぐに「スタート」に変更され、レースは開始されません。

コルーチンのスコープ

coroutineScope suspend 関数は CoroutineScope を作成し、指定された suspend ブロックを現在のスコープで呼び出します。スコープは、LaunchedEffect() スコープから coroutineContext を継承します。

このスコープは、指定されたブロックとそのすべての子コルーチンが完了するとすぐに返されます。RaceTracker アプリの場合、両方の参加者オブジェクトが run() 関数の実行を終了すると、返されます。

  1. raceInProgress フラグを更新する前に playerOneplayerTworun() 関数の実行が完了するように、両方の起動ビルダーを coroutineScope ブロックでラップします。
LaunchedEffect(playerOne, playerTwo) {
    coroutineScope {
        launch { playerOne.run() }
        launch { playerTwo.run() }
    }
    raceInProgress = false
}
  1. エミュレータまたは Android デバイスでアプリを実行します。次の画面が表示されます。

a85fc9550c9db86e.png

  1. スタートボタンをクリックします。プレーヤー 2 はプレーヤー 1 よりも速く走行します。レースが終了すると(両方のプレーヤーが 100% の進行状況に達すると)、一時停止ボタンのラベルが「スタート」に変わります。リセットボタンをクリックすると、レースをリセットしてシミュレーションを再実行できます。レースを次の動画で示します。

b7fa2ae4eb3a42df.gif

次の図に実行フローを示します。

cf724160fd66ff21.png

  • LaunchedEffect() ブロックが実行されると、制御は coroutineScope{..} ブロックに移ります。
  • coroutineScope ブロックは、両方のコルーチンを同時に起動し、実行が完了するのを待ちます。
  • 実行が完了すると、raceInProgress フラグが更新されます。

coroutineScope ブロックは、ブロック内のすべてのコードの実行が完了した後にのみ、実行を継続します。ブロックの外のコードでは、同時実行の有無は実装の詳細にすぎません。このコーディング スタイルは、同時実行プログラミングに対する構造化されたアプローチを提供するもので、構造化された同時実行と呼ばれます。

レースの完了後に [Reset] ボタンをクリックすると、コルーチンがキャンセルされ、両方のプレーヤーの進行状況が 0 にリセットされます。

ユーザーが [Reset] ボタンをクリックしたときにコルーチンがどのようにキャンセルされるかを確認するには、次の手順を行います。

  1. 次のコードに示すように、run() メソッドの本体を try-catch ブロックでラップします。
suspend fun run() {
    try {
        while (currentProgress < maxProgress) {
            delay(progressDelayMillis)
            currentProgress += progressIncrement
        }
    } catch (e: CancellationException) {
        Log.e("RaceParticipant", "$name: ${e.message}")
        throw e // Always re-throw CancellationException.
    }
}
  1. アプリを実行し、[Start] ボタンをクリックします。
  2. 進行状況の数値が増えたら、[Reset] ボタンをクリックします。
  3. 次のメッセージが Logcat に出力されていることを確認します。
Player 1: StandaloneCoroutine was cancelled
Player 2: StandaloneCoroutine was cancelled

7. コルーチンをテストする単体テストを作成する

コルーチンを使用する単体テストのコードの実行は、非同期、かつ複数のスレッド間で行われる可能性があるため、特別な注意が必要です。

テストで suspend 関数を呼び出すには、コルーチン内で行う必要があります。JUnit テスト関数自体は suspend 関数ではないため、runTest コルーチン ビルダーを使用する必要があります。このビルダーは kotlinx-coroutines-test ライブラリの一部であり、テストを実行するように設計されています。ビルダーは新しいコルーチンでテスト本体を実行します。

runTestkotlinx-coroutines-test ライブラリの一部であるため、その依存関係を追加する必要があります。

依存関係を追加するには、次の手順を行います。

  1. [Project] ペインの app ディレクトリにある、アプリ モジュールの build.gradle ファイルを開きます。

b112f0ae8f6398a6.png

  1. ファイル内で、dependencies{} ブロックが見つかるまで下にスクロールします。
  2. testImplementation 構成ファイルを使用して依存関係を kotlinx-coroutines-test ライブラリに追加します。
plugins {
    ...
}

android {
    ...
}

dependencies {
    ...
    testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.4'
}
  1. 次のスクリーンショットに示すように、build.gradle ファイルの上部にある通知バーで [Sync Now] をクリックし、インポートとビルドを終了します。

def0a9820607a08b.png

ビルドが完了したら、テストの作成を開始できます。

レースの開始と終了の単体テストを実装する

レースの各段階でレースの進行状況が正しく更新されるようにするには、単体テストでさまざまなシナリオに対応する必要があります。この Codelab では、次の 2 つのシナリオについて説明します。

  • レース開始後の進行状況。
  • レース終了後の進行状況。

レースの開始後にレースの進行状況が正しく更新されるかどうかを確認するには、raceParticipant.progressDelayMillis 期間が経過した後に現在の進行状況が 1 に設定されていることをアサートします。

テストシナリオを実装する手順は次のとおりです。

  1. テスト ソースセットの下にある RaceParticipantTest.kt ファイルに移動します。
  2. テストを定義するには、raceParticipant 定義の後に raceParticipant_RaceStarted_ProgressUpdated() 関数を作成し、@Test アノテーションを付けます。テストブロックは runTest ビルダーに配置する必要があるため、式の構文を使用して runTest() ブロックをテスト結果として返します。
class RaceParticipantTest {
    private val raceParticipant = RaceParticipant(
        ...
    )

    @Test
    fun raceParticipant_RaceStarted_ProgressUpdated() = runTest {
    }
}
  1. 読み取り専用の expectedProgress 変数を追加し、1 に設定します。
@Test
fun raceParticipant_RaceStarted_ProgressUpdated() = runTest {
    val expectedProgress = 1
}
  1. レースの開始をシミュレートするには、launch ビルダーを使用して新しいコルーチンを起動し、raceParticipant.run() 関数を呼び出します。
@Test
fun raceParticipant_RaceStarted_ProgressUpdated() = runTest {
    val expectedProgress = 1
    launch { raceParticipant.run() }
}

raceParticipant.progressDelayMillis プロパティの値によって、レースの進行状況が更新されるまでの時間が決まります。progressDelayMillis 時間が経過した後に進行状況をテストするには、テストになんらかの遅延を追加します。

  1. advanceTimeBy() ヘルパー関数を使用して、時間を raceParticipant.progressDelayMillis の値だけ進めます。advanceTimeBy() 関数を使用してテスト実行時間を短縮できます。
@Test
fun raceParticipant_RaceStarted_ProgressUpdated() = runTest {
    val expectedProgress = 1
    launch { raceParticipant.run() }
    advanceTimeBy(raceParticipant.progressDelayMillis)
}
  1. advanceTimeBy() は指定された時間にスケジュール設定されたタスクを実行しないので、runCurrent() 関数を呼び出す必要があります。この関数は、現在の時刻に保留中のタスクをすべて実行します。
@Test
fun raceParticipant_RaceStarted_ProgressUpdated() = runTest {
    val expectedProgress = 1
    launch { raceParticipant.run() }
    advanceTimeBy(raceParticipant.progressDelayMillis)
    runCurrent()
}
  1. 進行状況が確実に更新されるようにするには、assertEquals() 関数の呼び出しを追加して、raceParticipant.currentProgress プロパティの値が expectedProgress 変数の値と一致するかどうかを確認します。
@Test
fun raceParticipant_RaceStarted_ProgressUpdated() = runTest {
    val expectedProgress = 1
    launch { raceParticipant.run() }
    advanceTimeBy(raceParticipant.progressDelayMillis)
    runCurrent()
    assertEquals(expectedProgress, raceParticipant.currentProgress)
}
  1. テストを実行して、合格することを確認します。

レースの終了後、レースの進行状況が正しく更新されているかどうかを確認するには、レースの終了時に現在の進行状況が 100 に設定されていることをアサートします。

テストを実装する手順は次のとおりです。

  1. raceParticipant_RaceStarted_ProgressUpdated() テスト関数の後に、raceParticipant_RaceFinished_ProgressUpdated() 関数を作成し、@Test アノテーションを付けます。この関数は、runTest{} ブロックからテスト結果を返します。
class RaceParticipantTest {
    ...

    @Test
    fun raceParticipant_RaceStarted_ProgressUpdated() = runTest {
        ...
    }

    @Test
    fun raceParticipant_RaceFinished_ProgressUpdated() = runTest {
}
  1. launch ビルダーを使用して新しいコルーチンを起動し、その raceParticipant.run() 関数の呼び出しを追加します。
@Test
fun raceParticipant_RaceFinished_ProgressUpdated() = runTest {
    launch { raceParticipant.run() }
}
  1. レースの終了をシミュレートするには、advanceTimeBy() 関数を使用して、ディスパッチ時間を raceParticipant.maxProgress * raceParticipant.progressDelayMillis だけ進めます。
@Test
fun raceParticipant_RaceFinished_ProgressUpdated() = runTest {
    launch { raceParticipant.run() }
    advanceTimeBy(raceParticipant.maxProgress * raceParticipant.progressDelayMillis)
}
  1. runCurrent() 関数の呼び出しを追加して、保留中のタスクを実行します。
@Test
fun raceParticipant_RaceFinished_ProgressUpdated() = runTest {
    launch { raceParticipant.run() }
    advanceTimeBy(raceParticipant.maxProgress * raceParticipant.progressDelayMillis)
    runCurrent()
}
  1. 進行状況が正しく更新されるようにするには、assertEquals() 関数の呼び出しを追加して raceParticipant.currentProgress プロパティの値が 100 と等しいかどうかを確認します。
@Test
fun raceParticipant_RaceFinished_ProgressUpdated() = runTest {
    launch { raceParticipant.run() }
    advanceTimeBy(raceParticipant.maxProgress * raceParticipant.progressDelayMillis)
    runCurrent()
    assertEquals(100, raceParticipant.currentProgress)
}
  1. テストを実行して、合格することを確認します。

課題に挑戦しましょう

ViewModel の単体テストを作成するの Codelab で説明したテスト戦略を利用します。ハッピーパス、エラーケース、境界ケースを網羅するテストを追加します。

作成したテストと、解答コードで使用できるテストを比較します。

8. 解答コードを取得する

9. おわりに

お疲れさまでした。ここまで、コルーチンを使用して同時実行を処理する方法について学習しました。コルーチンは、メインスレッドをブロックしてアプリの応答を止める可能性のある長時間実行タスクの管理に役立ちます。また、コルーチンをテストする単体テストを作成する方法についても学習しました。

コルーチンには、次のような機能があります。

  • 読みやすさ: コルーチンを使用して記述するコードにより、コード行の実行順序がわかりやすくなります。
  • Jetpack の統合: Compose や ViewModel など、Jetpack ライブラリの多くには、コルーチンを全面的にサポートする拡張機能が用意されています。一部のライブラリでは、構造化された同時実行に使用できる独自のコルーチン スコープも用意されています。
  • 構造化された同時実行: コルーチンによって同時実行コードを安全かつ簡単に実装できるようにし、不要なボイラープレート コードを排除し、アプリで起動されたコルーチンの紛失や漏洩を防ぎます。

概要

  • コルーチンを使用すると、新しいプログラミング スタイルを学習することなく、同時実行する長時間実行コードを作成できます。設計上、コルーチンの実行は順次行われます。
  • suspend キーワードは関数または関数型をマークして、一連のコード命令の実行、一時停止、再開が可能であることを示すために使用されます。
  • suspend 関数は、別の suspend 関数からのみ呼び出すことができます。
  • 新しいコルーチンは、launch または async ビルダー関数を使用して開始できます。
  • コルーチンのコンテキスト、コルーチン ビルダー、ジョブ、コルーチン スコープ、ディスパッチャは、コルーチンを実装するための主要なコンポーネントです。
  • コルーチンは、ディスパッチャを使用して実行に使用するスレッドを決定します。
  • ジョブは、コルーチンのライフサイクルを管理し、親子関係を維持することで、構造化された同時実行を確保するうえで重要な役割を果たします。
  • CoroutineContext は、ジョブとコルーチン ディスパッチャを使用してコルーチンの動作を定義します。
  • CoroutineScope は、そのジョブを通じてコルーチンの存続期間を制御し、子とその子にキャンセルやその他のルールを再帰的に適用します。
  • 起動、完了、キャンセル、失敗の 4 つは、コルーチンの実行における一般的なオペレーションです。
  • コルーチンは構造化された同時実行の原則に従います。

詳細