1. AtsushiUemura

    No comment

    AtsushiUemura
Changes in body
Source | HTML | Preview

はじめに

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

準備

Coroutineを利用するために、build.gradleに下記の情報を追記します。
今回は2018/10/01時点での最新版(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

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

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()同様、Deffered<T>#await()を利用すれば、呼び出し先のコルーチンの終了まで呼び出し元のコルーチンを中断できます。

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

Sample

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

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

Suspending Function

コルーチンを中断できる関数をSuspending Functionと言います。
suspendをつけることで宣言できます。
コルーチン内かSuspending Function内からのみ実行できます。

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

Sample

delaySuspending Functionなので、実行できます。

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