StateFlow:UI向けのHotな状態保持
StateFlowをリアクティブな状態コンテナとして使い、ViewModelで監視します。
「StateFlow:UI向けのHotな状態保持」はCoddyKit上の無料Kotlin Academyレッスンです。 これはレッスン1/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはKotlin Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Kotlin Academyコースには全4レッスンが含まれています。
StateFlow とは
StateFlow は、常に値を持ち、すべてのコレクターに更新を発行する、状態を保持するホットな Flow です。最新の Kotlin アーキテクチャでは LiveData に置き換わるものです。
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
val stateFlow = MutableStateFlow(0) // initial value
println("Current: ${stateFlow.value}")
stateFlow.value = 42
println("Updated: ${stateFlow.value}")
}MutableStateFlow と StateFlow の違い
MutableStateFlow は内部で使用する可変の実装です。外部のオブザーバーには、キャストするか .asStateFlow() を使用して、読み取り専用の StateFlow を公開します。
import kotlinx.coroutines.flow.*
class CounterViewModel {
private val _count = MutableStateFlow(0) // mutable internally
val count: StateFlow<Int> = _count.asStateFlow() // read-only externally
fun increment() { _count.value++ }
fun decrement() { _count.value-- }
}StateFlow の収集
StateFlow は他の Flow と同じように収集します。収集を開始すると、最新の値がすぐに発行されます。
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
val state = MutableStateFlow("loading")
launch {
state.collect { println("State: $it") }
}
delay(50); state.value = "success"
delay(50); state.value = "idle"
delay(50)
coroutineContext.cancelChildren()
}StateFlow は重複値をまとめる
StateFlow は値が変化した場合にのみ発行します。同じ値を2回設定すると、発行は1回だけになります。連続する重複値をまとめるためです。
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
val flow = MutableStateFlow("A")
launch {
flow.collect { println("Received: $it") }
}
delay(50)
flow.value = "A" // no emission — same value
flow.value = "B" // emits
flow.value = "B" // no emission — same value
flow.value = "C" // emits
delay(50)
coroutineContext.cancelChildren()
}ViewModel での StateFlow
ViewModel の標準的なパターンは、ビジネスロジックが非公開の MutableStateFlow を変更し、UI が公開された StateFlow を監視する形です。
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
sealed class UiState { object Loading : UiState(); data class Success(val data: String) : UiState(); data class Error(val msg: String) : UiState() }
class MyViewModel(scope: CoroutineScope) {
private val _uiState = MutableStateFlow<UiState>(UiState.Loading)
val uiState: StateFlow<UiState> = _uiState.asStateFlow()
init {
scope.launch {
delay(100) // simulate load
_uiState.value = UiState.Success("Hello!")
}
}
}アトミックな変更には update()
update { } を使用すると、現在の値に基づいて状態をアトミックに更新できます。これは同時に更新が行われる場合に重要です。
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
val counter = MutableStateFlow(0)
List(100) {
launch(Dispatchers.Default) {
counter.update { it + 1 } // thread-safe atomic update
}
}.forEach { it.join() }
println("Counter: ${counter.value}") // 100
}楽観的な更新には compareAndSet
compareAndSet(expect, update) は、現在の値が expect と一致する場合にのみ新しい値を設定します。楽観的並行性制御に役立ちます。
import kotlinx.coroutines.flow.*
fun main() {
val state = MutableStateFlow("idle")
val changed = state.compareAndSet("idle", "loading")
println("Changed: $changed, Value: ${state.value}") // true, loading
val changed2 = state.compareAndSet("idle", "error") // won't change
println("Changed: $changed2, Value: ${state.value}") // false, loading
}StateFlow と LiveData の違い
StateFlow は Android のライフサイクルなしで動作します。LiveData はライフサイクルを認識しますが、Android 専用です。共有 KMP ViewModel には StateFlow を推奨します。
import kotlinx.coroutines.flow.*
// StateFlow: pure Kotlin, works in commonMain
// val state = MutableStateFlow("value")
// LiveData: Android-only, lifecycle-aware
// val liveData = MutableLiveData("value")
// In Compose, collect StateFlow with:
// val state by viewModel.uiState.collectAsState()
fun main() { println("StateFlow: multiplatform; LiveData: Android-only") }stateIn:Cold Flow を StateFlow に変換する
flow.stateIn(scope, started, initialValue) は Cold Flow をホットな StateFlow に変換し、すべてのコレクターで1つのサブスクリプションを共有します。
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
val cold = flow {
println("Fetching...")
delay(100)
emit("data")
}
val hot: StateFlow<String> = cold.stateIn(
scope = this,
started = SharingStarted.Lazily,
initialValue = "loading"
)
launch { hot.collect { println("A: $it") } }
launch { hot.collect { println("B: $it") } }
delay(200)
coroutineContext.cancelChildren()
}SharingStarted の戦略
Eagerly:すぐに開始します。Lazily:最初のコレクターで開始します。WhileSubscribed(stopTimeout):コレクターがいなくなると停止し、コレクターが登録されると再開します。
import kotlinx.coroutines.flow.*
// Eagerly: upstream starts right away
// SharingStarted.Eagerly
// Lazily: waits for first subscriber
// SharingStarted.Lazily
// WhileSubscribed: stops 5s after last subscriber
// SharingStarted.WhileSubscribed(5000)
// Typical ViewModel usage:
// val uiState = repo.dataFlow.stateIn(viewModelScope, WhileSubscribed(5000), Loading)派生状態の監視
map + stateIn を使用して、既存の StateFlow から新しい StateFlow を派生させます。派生したフローは、元のフローが変化するたびに更新されます。
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
val count = MutableStateFlow(5)
val doubled = count.map { it * 2 }.stateIn(this, SharingStarted.Eagerly, 10)
println(doubled.value) // 10
count.value = 7
delay(50)
println(doubled.value) // 14
coroutineContext.cancelChildren()
}クイックチェック
StateFlow に同じ値を2回設定するとどうなりますか。
振り返り
StateFlow は、常に値を持ち、重複値をまとめるホットな Flow です。内部では MutableStateFlow を使用し、外部には StateFlow を公開します。並行した変更には update() を使用し、Cold Flow の変換には stateIn() を使用します。
よくある質問
「StateFlow:UI向けのHotな状態保持」レッスンは無料ですか?
はい。「StateFlow:UI向けのHotな状態保持」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Kotlin Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Kotlin Academyコースには全4レッスンが含まれています。
「StateFlow:UI向けのHotな状態保持」で何を学びますか?
StateFlowをリアクティブな状態コンテナとして使い、ViewModelで監視します。 ブラウザで直接実行するハンズオンコードでKotlin Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Kotlin Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのKotlin Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン1/4です。
「StateFlow:UI向けのHotな状態保持」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このKotlin Academyレッスンでコードを書いて実行できますか?
はい。すべてのKotlin Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- StateFlow:UI向けのHotな状態保持
- SharedFlow:イベントバスとワンショットイベント
- shareInとstateInでCold FlowをHotに変換する
- TurbineによるStateFlowとSharedFlowのテスト