Skip to content

Instantly share code, notes, and snippets.

@sahara-ooga
Last active November 24, 2019 11:58
Show Gist options
  • Save sahara-ooga/b1a0bf585fbe5b0a30d2628bbfb659f8 to your computer and use it in GitHub Desktop.
Save sahara-ooga/b1a0bf585fbe5b0a30d2628bbfb659f8 to your computer and use it in GitHub Desktop.
Kotlin Coroutine

CoroutineScope

Coroutine scope is responsible for the structure and parent-child relationships between different coroutines.

トップレベルではDispatchers.Mainを指定し、適宜子コルーチンでバックグラウンドで良い場合にasync(Dispatchers.Default)としてバックグラウンド化する。

runBlocking

スレッドをブロックする。スコープ内の処理の実行が完了するまでスレッドをブロックする

viewModelScope

ViewModelクラスで使える。 ViewModel#onCleared() のタイミングでキャンセルされる。

GlobalScope

アプリケーションの有効期間全体にわたって動作するためGlobalScopeを同一アプリ内で乱用すると不都合が発生したりAndroidのアプリケーションライフサイクルとの間で問題が発生する可能性もあります。

launch function

This computation is suspendable: while performing the network requests, it gets "suspended" and releases the underlying thread. When the network request returns the result, the computation is resumed.

launch is used for starting a computation that isn't expected to return a specific result.

launch returns Job, which represents the coroutine. It is possible to wait until it completes by calling Job.join().

coroutineScope function

This function is designed for parallel decomposition of work.

async

An async call can return a Deferred or Deferred depending on what the lambda returns (the last expression inside the lambda is the result).

    import kotlinx.coroutines.*

    fun main() = runBlocking {
        val deferred: Deferred<Int> = async {//このラムダ式の中は、スレッドプールの中から選ばれたスレッドで実行される
            loadData()
        }
        println("waiting...")
        println(deferred.await())//awaitで、defferdの値が戻ってくるまでメインスレッドの処理を止める
    }
    
    /**
    * 中断関数
    */
    suspend fun loadData(): Int {
        println("loading...")
        delay(1000L)
        println("loaded!")
        return 42
    }

awaitAll

複数のasyncな処理を開始後、全ての結果が返ってくるまで待つ。

import kotlinx.coroutines.*

fun main() = runBlocking {
    val deferreds: List<Deferred<Int>> = (1..3).map {
        async {
            delay(1000L * it)
            println("Loading $it")
            it
        }
    }
    val sum = deferreds.awaitAll().sum()//すべての結果が帰ってくるまで待つ
    println("$sum")
}

Dispatchers

coroutineが実行されるスレッドを指定する

async()(指定なし) -> If we don't specify one as an argument, then async will use the dispatcher from the outer scope. async(Dispatchers.Default) -> システム側でスレッドプールから適宜割り当てる

242 [AWT-EventQueue-0] INFO  Contributors - Clearing result
3453 [AWT-EventQueue-0 @coroutine#1] INFO  Contributors - kotlin: loaded 47 repos
3763 [DefaultDispatcher-worker-3 @coroutine#3] INFO  Contributors - kotlin-examples: loaded 25 contributors
3865 [DefaultDispatcher-worker-3 @coroutine#4] INFO  Contributors - ts2kt: loaded 11 contributors
3901 [DefaultDispatcher-worker-2 @coroutine#7] INFO  Contributors - kotlin-benchmarks: loaded 7 contributors
3907 [DefaultDispatcher-worker-1 @coroutine#6] INFO  Contributors - dokka: loaded 37 contributors
3913 [DefaultDispatcher-worker-3 @coroutine#5] INFO  Contributors - kotlin-koans: loaded 44 contributors
4018 [DefaultDispatcher-worker-4 @coroutine#10] INFO  Contributors - anko-example: loaded....

スレッド

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

中断

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

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

The major difference with a blocking version is that instead of blocking the thread, we suspend the coroutine:

thread -> coroutine 
block -> suspend

Context

launch(Dispatchers.Main) { ... }.join() is equivalent to withContext(Dispatchers.Main) { ... }

Reference

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment