0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

自分用 Flowについて簡単にまとめてみた

Last updated at Posted at 2023-12-10

Kotlin独自の機能ピックアップ
Flowについて簡単にまとめてみました。

Flowとは?

コルーチンをベースにした非同期プログラミングのうち、
Flowは「連続的な非同期なデータ」を表現し、処理するための機能です。
そのため、Flowを非同期に処理を行える「データ ストリーム」と考えることもできます。

データ ストリームには、以下の 3 つのエンティティがあります。
プロデューサ
ストリームに出力するデータを生成します。コルーチンであるため、Flow は非同期にデータを生成できます。
インターミディアリ
ストリームに出力された各値またはストリームそのものを変更できます。(必要な場合)
コンシューマ
ストリームから得られた値を使用します。
引用(https://developer.android.com/kotlin/flow?hl=ja)

Flowの使い方

Flowを使うには、FlowビルダーAPIを使用します。
まずは以下のコードを見てみてください。

import kotlinx.coroutines
import kotlinx.coroutines.flow

fun sampleFlow() = flow {
    for (i in 1..3) {
        delay(1000) // 非同期処理の模擬
        emit(i)     // 値を生成
    }
}

fun main() {
    CoroutineScope(Dispatchers.IO).launch {
            sampleFlow()
                .collect { value ->
            println(value)
        }
    }
}
// main()を呼んだ結果
1,2,3

これを細かく解説していきます。

sampleFlow()の処理

プロデューサの役割を果たし、ストリームに出力するデータを生成します。
Flow <Int>
Flow<Int>は、非同期で整数の連続的なストリームを表現するための型です
flow{~~~}
=でつながれているflow{~~~}は、Flowを生成するための flowビルダー関数です。
flowビルダー関数の中では、連続的な非同期なデータを処理します。
emit()
データを処理したあとは、emit()(直訳=放出)して値を生成します。

fun sampleFlow() = flow {
    for (i in 1..3) {
        delay(1000) // 非同期処理の模擬
        emit(i)     // 値を生成
    }
}

今回のコードはiが3になるまでの処理を非同期でwhile(true){~}で繰り返しデータを生成し続けることも可能です。
しかし、あくまでもデータを生成しただけでこのままでは使用することができません。

main()の処理

CoroutineScope(Dispatchers.IO).launch{~~~}
非同期に処理を行うことができます。
sampleFlow().collect {~}
この中の処理は順序だてて説明します。
①一番最初にsampleFlow() 関数が呼ばれ、flow { ... } ビルダー内のコードが非同期に実行されます。しかしまだデータは発行されるわけではありません。
②simpleFlow()の戻り値である Flowインスタンスが得られます。
③.collect { println(it) } メソッドが呼ばれると、実際にデータの生成が開始されます。(トリガー)この時、flowビルダー内のコードが実行され、1から3までの整数が順次発行されます。
④各データ(Value)が発行されるたびに、collectメソッドのラムダ式が実行され、println(it)が呼ばれます

fun main() {
    CoroutineScope(Dispatchers.IO).launch {
            sampleFlow()
                .collect { value ->
            println(value)
        }
    }
}

その他のメソッド

Flow クラスには、さまざまなメソッドが提供されており、これらを組み合わせて
データを操作できます。

.map
.map メソッドは、各要素に対して変換関数を適用し、新しい要素のFlowを生成します。
しかし、実際に新しい要素を発行するのではなく、変換された要素が元の Flow の要素として発行されます。

// map 各要素を2倍に変換
sampleFlow()
    .map { it * 2 }
    .collect { println(it) }
// 出力:2,4,6

.filter:
.filter メソッドは、条件に合致する要素だけを含む新しい Flow を生成します。

// 2. filter: 条件を満たす要素だけを含む
simpleFlow()
    .filter { it > 1 }
    .collect { println(it) }
// 出力:2,3

.transform
.transform メソッドは、各要素に対して変換関数を適用し、新しい要素を発行するための柔軟なメソッドです。

// 3. transform: 各要素を2倍に変換
simpleFlow()
    .transform { emit(it * 2) }
    .collect { println(it) }
// 出力:2,4,6

.onEach
.onEach メソッドは、各要素に対して副作用を実行し、元の Flow をそのまま返します。

// 4. onEach: 各要素を処理しても元のFlowは変わらない
simpleFlow()
    .onEach { println("Processing: $it") }
    .collect { println(it) }
// 出力: Processing: 1,1, Processing: 2,2, Processing: 3,3

.zip
.zip メソッドは、複数の Flow を結合し、対応する位置の要素をペアとして新しい Flow を生成します。

// 5. zip: 2つのFlowを組み合わせて新しいFlowを生成
val flow1 = flowOf(1, 2, 3)
val flow2 = flowOf("A", "B", "C")
flow1.zip(flow2) { a, b -> "$a - $b" }
        .collect { println("zip: $it") }
// 出力: zip: 1 - A, zip: 2 - B, zip: 3 - C

.flatMapConcat 
.flatMapConcat メソッドは、各要素に対して非同期に別の Flow を生成し、それらの Flow を直列に結合します。

// 6. flatMapConcat: 各要素に対して別のFlowを生成し、直列に結合
simpleFlow()
    .flatMapConcat { flowOf(it, it * 2, it * 3) }
    .collect { println(it) }
    // 出力: 1,2,3,2,4,6,3,6,9

最後に

flow難しい!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?