コルーチン(Coroutine)は「非同期処理の手法」の1つです。
Kotlinが提供します。
特徴としてnon-blocking動作をサポートします。
このnon-blocking動作についてまとめます。
delay( )とThread.sleep( )の違い
サンプル(A)(B)は「3⇒2⇒1⇒0」と1秒の間隔でカウントダウンを行うプログラムです。
1秒の間隔を作るために、1つは(A)コルーチンのdelay( )を使い、もう1つは(B)Thread.sleep( )を使っています。(B)は単にdelay( )をThread.sleep( )に置き換えたものです。
val _txtCount = findViewById<TextView>(R.id.txtCount)
val _btnStart = findViewById<Button>(R.id.btnStart)
val _btnStop = findViewById<Button>(R.id.btnStop)
var _job: Job? = null
_btnStart.setOnClickListener {
_job?.cancel() // 起動が重複した時、前のタスクをキャンセル
_job = GlobalScope.launch(Dispatchers.Main) { // Mainスレッドを起動
_txtCount.text = "3"
delay(1000) // 1秒の間隔を作る
_txtCount.text = "2"
delay(1000) // 1秒の間隔を作る
_txtCount.text = "1"
delay(1000) // 1秒の間隔を作る
_txtCount.text = "0"
}
}
_btnStop.setOnClickListener {
_job?.cancel()
}
val _txtCount = findViewById<TextView>(R.id.txtCount)
val _btnStart = findViewById<Button>(R.id.btnStart)
val _btnStop = findViewById<Button>(R.id.btnStop)
var _job: Job? = null
_btnStart.setOnClickListener {
_job?.cancel() // 起動が重複した時、前のタスクをキャンセル
_job = GlobalScope.launch(Dispatchers.Main) { // Mainスレッドを起動
_txtCount.text = "3"
Thread.sleep(1000) // 1秒の間隔を作る
_txtCount.text = "2"
Thread.sleep(1000) // 1秒の間隔を作る
_txtCount.text = "1"
Thread.sleep(1000) // 1秒の間隔を作る
_txtCount.text = "0"
}
}
_btnStop.setOnClickListener {
_job?.cancel()
}
【(A)の実行結果 】
STARTのクリックで実行:OK
【(B)の実行結果 】
STARTのクリックで変化なし:NG
(A)コルーチンのdelay( )を使った例は正常に動きますが、(B)Thread.sleep( )を使った例はSTARTボタンを押してもカウントダウンしません。
delay( )もThread.sleep( )も「1秒の間隔を作る」構文であることに、違いは無いのですが…
これはスレッドの扱われ方の違いから生じています。
non-blocking動作のdelay( )
delay( )は実行後にスレッドを一時停止(suspend)します。
一時停止したスレッドはプールに返却されて、新たな処理へ割り当てられるまで待機します。処理の要求があれば、プールから取得したスレッドへ割り当てます。
つまり、スレッドは新たな処理の割り当てを拒否しません。
これをnon-blocking動作といいます。
サンプル(A)は1秒の間隔を作る間に画面描画(新たな処理)が実行できるので、アプリは正常に動作します。
blocking動作のThread.sleep( )
sleep( )は実行後にスレッドを休止(sleep)します。
休止したスレッドは「休止」という処理を続けています。稼働した状態と同じで、新たな処理が割り当てできません。
つまり、スレッドは新たな処理の割り当てを拒否します。
これをblocking動作といいます。
コルーチンを処理している間、スレッドはシステムが発行する画面描画の実行も拒否します。サンプル(B)は、これが原因で画面は更新されず、アプリは何も変化しない見た目になります。
Susupend関数とは
non-blocking動作を含んでいる関数のことをSuspend関数と呼びます。
Suspend関数は関数名の前にsuspend修飾子を付ける決まりになっています。
delay( )はSuspend関数です。ですので、suspend修飾子が付いています。
public suspend fun delay(timeMillis: Long) {
if (timeMillis <= 0) return // don`t delay
return suspendCancellableCoroutine sc@ { cont: CancellableContinuation<Unit> ->
cont.context.delay.scheduleResumeAfterDelay(timeMillis, cont)
}
}
※詳細は「Susupend関数とその仕組み」を参照
non-blocking動作≒「スレッド+コールバック」
コルーチンのSuspend関数が利用可能になる以前は、non-blocking動作を「スレッド+コールバック」で表現していました。
例えばdelay( )は次のようになります。
_txtCount.text = "2"
delay(1000)
_txtCount.text = "1"
_txtCount.text = "2"
_thread = Thread { // スレッド
try { Thread.sleep(1000) }
catch (e: InterruptedException) { return@Thread }
runOnUiThread { // コールバック
_txtCount.text = "1"
}
}.apply { start() }
「スレッド+コールバック」の欠点は、
(1)non-blocking動作毎にThreadのインスタンスを作成
⇒起動のオーバーヘッドが大きい
(2)コールバック後にThreadインスタンスは不要
⇒破棄される、GCまでメモリにゴミが残る
です。
コルーチンはスレッドをプールから再利用するので、上記の欠点がありません。よくコルーチンのメリットとして述べられている点です。
関連記事:
近頃の携帯端末はクワッドコア(プロセッサが4つ)やオクタコア(プロセッサが8つ)が当たり前になりました。 サクサク動作するアプリを作るために、この恩恵を使わなければ損です。 となると、必然的に非同期処理(マルチスレッド)を使うことになります。 JavaのThreadクラス、Android APIのAsyncTaskクラスが代表的な手法です。 Kotlinは上記に加えて「コルーチン(Coroutine)」が使えるようになっています。 今回は、このコルーチンについて、まとめます。 ...
コルーチン(Coroutine)は「非同期処理の手法」の1つです。 Kotlinが提供します。 コルーチンの構成要素であるSuspend関数について、まとめます。 ...
コルーチン(Coroutine)は「非同期処理の手法」の1つです。 Kotlinが提供します。 コルーチンはビルダー(Builder)により開始されます。 ビルダーは3つの種類があり、その中の1つがlaunchです。 このlaunchビルダーについて、まとめます。 ...
コルーチン(Coroutine)は「非同期処理の手法」の1つです。 Kotlinが提供します。 コルーチンを開始するlaunchビルダーの仕組みについて、まとめます。 ※仕組みの解析は次のバージョンを対象に行っています。 Kotlin:Ver 1.6.10 org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9 ...
コルーチン(Coroutine)は「非同期処理の手法」の1つです。 Kotlinが提供します。 コルーチンはビルダー(Builder)により開始されます。 ビルダーは3つの種類があり、その中の1つがasyncです。 このasyncビルダーについて、まとめます。 ...
コルーチン(Coroutine)は「非同期処理の手法」の1つです。 Kotlinが提供します。 コルーチンを開始するasyncビルダーの仕組みについて、まとめます。 ※仕組みの解析は次のバージョンを対象に行っています。 Kotlin:Ver 1.6.10 org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9 ...
コルーチン(Coroutine)は「非同期処理の手法」の1つです。 Kotlinが提供します。 コルーチンはビルダー(Builder)により開始されます。 ビルダーは3つの種類があり、その中の1つがrunBlockingです。 このrunBlockingビルダーについて、まとめます。 ...
CoroutineContextはコルーチンで起動されるスレッドの属性を格納しています。 その中にコルーチンの名前を表現するName属性があります。 Name属性を出力する方法を紹介します。 ...
コルーチン(Coroutine)は「非同期処理プログラミングの手法」の1つです。 Kotlinが提供します。 withContextはCoroutineContextを切り替えてスレッドを起動するSuspend関数です。 このwithContextについて、まとめます。 ...
コルーチン間でメッセージ(データ)の送受信を行うことが出来ます。 ここで紹介する「メッセージの送受信」を使えば、非同期処理の間で確実にデータを受け渡し出来ます。 それにより、非同期処理の連携が容易になります。 今回は、メッセージの送受信についての基礎と、Channelを使った最も基本的な送受信の動作をまとめます。 ※環境:Android Studio Flamingo | 2022.2.1 :org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4 ...
KotlinのコルーチンAPIは「コルーチン間でメッセージを送受信する仕組み」を提供しています。 Channel、Produce、Flow、SharedFlow、StateFlowなどです。 これらは、「メッセージを送受信する」という本命の動作は変わりませんが、特徴や違いを持ちます。 プログラミングで利用する際は、特徴や違いを理解して、使い分けが必要になります。 ですので、各々を比較しつつ、まとめました。 この記事は「Produce」について、まとめたものです。 ※環境:Android Studio Koala Feature Drop | 2024.1.2 Kotlin 1.9.0 Compose Compiler 1.5.1 org.jetbrains.kotlinx:kotlinx-coroutines-android 1.7.3 org.jetbrains.kotlinx:kotlinx-coroutines-core 1.7.3 ...
KotlinのコルーチンAPIは「コルーチン間でメッセージを送受信する仕組み」を提供しています。 Channel、Produce、Flow、SharedFlow、StateFlowなどです。 これらは、「メッセージを送受信する」という本命の動作は変わりませんが、特徴や違いを持ちます。 プログラミングで利用する際は、特徴や違いを理解して、使い分けが必要になります。 ですので、各々を比較しつつ、まとめました。 この記事は「Flow」について、まとめたものです。 ※環境:Android Studio Koala Feature Drop | 2024.1.2 Kotlin 1.9.0 Compose Compiler 1.5.1 org.jetbrains.kotlinx:kotlinx-coroutines-android 1.7.3 org.jetbrains.kotlinx:kotlinx-coroutines-core 1.7.3 ...
KotlinのコルーチンAPIは「コルーチン間でメッセージを送受信する仕組み」を提供しています。 Channel、Produce、Flow、SharedFlow、StateFlowなどです。 これらは、「メッセージを送受信する」という本命の動作は変わりませんが、特徴や違いを持ちます。 プログラミングで利用する際は、特徴や違いを理解して、使い分けが必要になります。 ですので、各々を比較しつつ、まとめました。 この記事は「SharedFlow」について、まとめたものです。 ※環境:Android Studio Koala Feature Drop | 2024.1.2 Kotlin 1.9.0 Compose Compiler 1.5.1 org.jetbrains.kotlinx:kotlinx-coroutines-android 1.7.3 org.jetbrains.kotlinx:kotlinx-coroutines-core 1.7.3 ...
KotlinのコルーチンAPIは「コルーチン間でメッセージを送受信する仕組み」を提供しています。 Channel、Produce、Flow、SharedFlow、StateFlowなどです。 これらは、「メッセージを送受信する」という本命の動作は変わりませんが、特徴や違いを持ちます。 プログラミングで利用する際は、特徴や違いを理解して、使い分けが必要になります。 ですので、各々を比較しつつ、まとめました。 この記事は「StateFlow」について、まとめたものです。 ※環境:Android Studio Koala Feature Drop | 2024.1.2 Kotlin 1.9.0 Compose Compiler 1.5.1 org.jetbrains.kotlinx:kotlinx-coroutines-android 1.7.3 org.jetbrains.kotlinx:kotlinx-coroutines-core 1.7.3 ...
Flowはメンバー関数や拡張関数で様々な機能を提供しています。 これらの関数は大きく分けて、中間演算(Intermediate operators)と終端演算(Terminal operators)に分けられます。 中間演算とは、withIndex、map、filter、drop、take、zip、merge、combineなどです。通信経路(Flow)の途中に位置して、ストリームデータを変更したり、Flowを統合したりします。 終端演算とは、collect、single、reduce、toListなどです。通信経路の末端に位置して、ストリームデータを収集します。 今回は、この「Flowの中間演算」のwithIndex、map、filter、drop、takeを取り上げて、まとめます。 ※環境:Android Studio Koala Feature Drop | 2024.1.2 Patch 1 Kotlin 1.9.0 Compose Compiler 1.5.1 org.jetbrains.kotlinx:kotlinx-coroutines-androi ...
Flowはメンバー関数や拡張関数で様々な機能を提供しています。 これらの関数は大きく分けて、中間演算(Intermediate operators)と終端演算(Terminal operators)に分けられます。 中間演算とは、withIndex、map、filter、drop、take、zip、merge、combineなどです。通信経路(Flow)の途中に位置して、ストリームデータを変更したり、Flowを統合したりします。 終端演算とは、collect、single、reduce、toListなどです。通信経路の末端に位置して、ストリームデータを収集します。 今回は、この「Flowの中間演算」のzip、merge、combineを取り上げて、まとめます。 ※環境:Android Studio Koala Feature Drop | 2024.1.2 Patch 1 Kotlin 1.9.0 Compose Compiler 1.5.1 org.jetbrains.kotlinx:kotlinx-coroutines-android 1.7.3 o ...