はじめに
Androidアプリを作るとき、画面に表示するデータや、ユーザーがボタンを押したといった「イベント」を、プログラムの中でスムーズにやり取りする仕組みが必要です。
Kotlinコルーチンという技術には、そのための便利なツールとして「StateFlow(ステートフロー)」と「SharedFlow(シェアードフロー)」があります。
💡 ホットフローとは?(ラジオ放送の例)
「ホットフロー」とは、聴く人(コレクタ/購読者)がいるかどうかに関係なく、常に情報を発信し続けているデータの流れのことです。まるで、放送局が24時間常に電波を出し続けているラジオ放送のようなものです。
これに対して「コールドフロー」(通常のFlow
)は、誰かが「聴き始めます」と言って初めて放送を開始します。
StateFlowとSharedFlowは、この「常に流れている」データをアプリのあちこちに共有するために使われます。
1. StateFlow:常に最新を示す「スコアボード」
StateFlowは、アプリの**「今の状態」**を伝えることに特化した仕組みです。
例えるなら、**スポーツ試合の「スコアボード」**です。
特徴(スコアボードのルール)
特徴 | スコアボードでの役割 | 根拠となる情報 |
---|---|---|
常に値を持つ | 試合開始時(アプリ起動時)から「0対0」など、必ず初期値が表示されています。 |
StateFlow は初期値をコンストラクタで渡す必要があります。 |
最新の値だけ | 10点が連続で入っても、画面が更新されるのは最終的な最新の点数だけです。 |
StateFlow は現在の値をvalue プロパティで取得できます。 |
同じ値を無視 | スコアが「5対5」のまま変わらない場合、ボードは何度も「5対5」を再表示しません。 |
連続する同じ値は無視されます (distinctUntilChanged と同じ仕組み)。 |
StateFlowの使いどころ
StateFlowは、画面に表示すべきデータ、つまりUIの状態を管理するために最適です。
- 例: ニュース記事のリスト、読み込み中の表示(ローディングスピナー)、現在のエラーメッセージなど。
- メリット: 画面の向きを変える(設定変更)などがあっても、常に最新の状態をUIに保つことができます。
2. SharedFlow:一度きりの「イベントのピストル」
SharedFlowは、StateFlowよりも自由度の高い仕組みで、主に**「何か出来事(イベント)が起こった」**ことを複数の場所に伝える役割を持ちます。
例えるなら、**運動会のスタートで鳴らす「ピストル」**です。
特徴(ピストルの合図のルール)
特徴 | ピストルの役割 | 根拠となる情報 |
---|---|---|
状態を持たない | ピストルが鳴る前に「今の音」は存在しません。 |
SharedFlow は初期値を必要としません。 |
イベントを伝える | 「パン!」という音が鳴ったら、その瞬間にイベントが送られます。 | 主に画面遷移やトースト表示などのワンショットイベントに使われます。 |
同じ値も区別できる | (設定次第で) 「パン!パン!」と連続で鳴ったら、それを2つのイベントとして処理できます。 |
StateFlow と異なり、連続する同じ値も放出可能です。 |
高度な設定 | 新しい人が途中から聞きに来ても、直前のイベントを何個か教えてあげる(リプレイ機能)など、細かく設定できます。 |
replay 、extraBufferCapacity などの設定が可能です。 |
SharedFlowの使いどころ
SharedFlow
は、一度だけ実行すれば完了するアクションを複数のコンポーネントに通知したい場合に最適です。
- 例: ユーザーがボタンをクリックした。画面の下にメッセージ(トーストやスナックバー)を一瞬だけ表示したい。ある画面から別の画面へ移動する(ナビゲーション)。
- メリット: UIのイベント処理を一元化し、コードの可読性を向上させることができます。
3. まとめ:StateFlowとSharedFlowの使い分け
StateFlow
は、SharedFlow
が「最新の1つだけをリプレイし」「初期値を持ち」「連続した同じ値を無視する」という設定に固定され、最適化された状態特化型のFlowです。
目的 | StateFlow (スコアボード) | SharedFlow (ピストル/イベント) |
---|---|---|
何を表すか | 現在の状態。常に最新の値だけ。 | 瞬間的な出来事(イベント)。 |
初期値 | 必須。 | 不要(デフォルト)。 |
同じ値が連続 | 無視される(UIの無駄な更新を防ぐ)。 | 通常放出される(イベントは発生した回数分必要)。 |
主な用途 | UIの状態管理 (画面に表示するデータ)。 | ワンショットイベント (ナビゲーション、トースト表示)。 |
Androidアーキテクチャにおける流れ
Androidの推奨アーキテクチャでは、ViewModelがUI層とデータ層の間に位置し、UIの状態を管理する重要な役割を担います。
-
データ層: データソース(データベースやネットワーク通信)は、
SharedFlow
や通常のFlow
を使ってデータを流すことがあります。 -
ViewModel: ここで流れてきたデータを、UIが扱いやすいように**
StateFlow
**に変換し、UIに公開します。- この変換には
stateIn
という便利な機能が使われます。
- この変換には
-
UI層(画面): UIは
StateFlow
を監視し、値が変わるたびに画面を更新します。
⚠️ 大事な注意点:安全な使い方
StateFlow
やSharedFlow
をAndroidのUI(画面)で使うとき、画面が裏に隠れても(STOPPED
状態になっても)データの収集(collect
)を止め忘れると、アプリが無駄な動きをしたり、クラッシュしたりする可能性があります。
これを防ぐため、Androidでは画面のライフサイクル(生存期間)に合わせて、repeatOnLifecycle
や flowWithLifecycle
といった安全な方法でフローを収集することが強く推奨されています。