1. 84d010m08
Changes in body
Source | HTML | Preview

はじめに

Kotlin 1.1からCoroutineが実験的に組み込まれました。
Coroutineとは「特定のスレッドに束縛されない、中断可能な計算インスタンス」です。
非同期処理で用いられますが、Threadよりも軽量で、実行途中で処理を中断・再開することができます。

準備

Coroutineを利用するために、build.gradleに下記の情報を追記します。
今回は2018/09/30時点での最新版(0.30.0)を使用しています。
更新状況はここから確認できます。

build.gradle
dependencies {
    ...
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:0.30.0"
}
build.gradle
kotlin {
    experimental {
        coroutines 'enable'
    }
}
build.gradle
repositories {
    jcenter()
}

使い方

Coroutineの作成にはCoroutineビルダーを使用します。

runBlocking

現在のスレッドをブロックするビルダーです。任意の型を返します。

runBlocking {
    // 何かしらの処理
}

Sample

fun main(args:Array<String>) {
    println(1)
    runBlocking {
        println(2)
    }
    println(3)
}

/**
 * 実行結果
 * 1
 * 2
 * 3
 */

launch

戻り値としてJobを返すビルダーです。

0.26.1からlaunchGlobalScope.launchになりました。

GlobalScope.launch {
    // 何かしらの処理 
}

Sample

現在のスレッドをブロックしないため、launch内の処理が実行される前にプログラムが終了します。

fun main(args:Array<String>) {
    println(1)
    launch {
        println(2)
    }
    println(3)
}

/**
 * 実行結果
 * 1
 * 3
 */

引数で実行するスレッドを指定できます。
引数なしの場合はDispatchers.Defaultが設定されます。

0.26.1からCommonPoolDispatchers.Defaultになりました。
0.26.1からUIDispatchers.Unconfinedになりました。

/**
 * Dispatchers.Default -> バックグラウンドスレッド
 * Dispatchers.Unconfined -> メインスレッド
 */
GlobalScope.launch(Dispatchers.Unconfined) {
    // 何かしらの処理 
}

Job#join()を利用すれば、呼び出し先のcoroutineの終了まで呼び出し元のcoroutineを中断できます。

runBlocking {
    GlobalScope.launch() {
        // 何かしらの処理 
    }.join()
}

Sample

fun main(args:Array<String>) = runBlocking {
    println(1)
    GlobalScope.launch {
        println(2)
    }.join()
    println(3)
}

/**
 * 実行結果
 * 1
 * 2
 * 3
 */

async

戻り値としてDeferred<T>を返すビルダーです。
Coroutineの処理が終わったタイミングで戻り値を取得できます。

0.26.1からasyncGlobalScope.asyncになりました。

GlobalScope.async {
    // 何かしらの処理 
}

Sample

launch同様、現在のスレッドをブロックしないため、async内の処理が実行されません。

fun main(args:Array<String>) {
    println(1)
    GlobalScope.async {
        println(2)
    }
    println(3)
}

/**
 * 実行結果
 * 1
 * 3
 */

Job#join()同様、Deferred<T>#await()を利用すれば、呼び出し先のCoroutineの終了まで呼び出し元のCoroutineを中断できます。

runBlocking {
    GlobalScope.async {
        // 何かしらの処理 
    }.await()
}

Sample

fun main(args:Array<String>) = runBlocking {
    println(1)
    GlobalScope.async {
        println(2)
    }.await()
    println(3)
}

/**
 * 実行結果
 * 1
 * 2
 * 3
 */

Suspend関数

Coroutineを中断できる関数です。suspendをつけることで宣言できます。
CoroutineかSuspend関数内からのみ実行できます。

suspend fun sampleSuspending(){
     // 何かしらの処理       
}

Sample

delayはSuspend関数なので実行できます。

fun main(args:Array<String>) = runBlocking {
    println(1)
    sampleSuspending()
    println(3)
}

suspend fun sampleSuspending() {
    delay(1000)
    println(2) 
}

/**
 * 実行結果
 * 1
 * (1秒中断)
 * 2
 * 3
 */ 

まとめ

非同期処理を直感的に理解しやすく、とても簡潔に記述できるようになりました。

参考

Coroutines - Kotlin Programming Language
AndroidでKotlin Coroutinesを使ってみる
eaglesakuraの技術ブログ
Kotlin の Coroutine を概観する
入門Kotlin coroutines