以下のような ViewModel があったとして、バッキングプロパティ部分。
どう書いてますか。
class CounterModel {
private val _counter = MutableStateFlow(0)
??? counter ??? = _counter ???
fun inc() {
_counter.update { count -> count + 1 }
}
}
以下の登場時の開発の様子を参考に。
👉 Introduce StateFlow · Issue #1973 · Kotlin/kotlinx.coroutines
StateFlow は、状態を表す更新可能な値の Flow です。
- StateFlow インターフェイスは、現在の値にアクセスするための読み取り専用で、値の更新を collect するための Flow を実装しています。
- MutabaleStateFlow インターフェースは、値を変更する操作を追加しています。
- MutableStateFlow(x) のコンストラクタ関数が用意されています。この関数は、与えられた初期値を持つ MutableStateFlow の実装を返します。値への高速で非リアクティブなアクセスが必要な場合は StateFlow として、値への更新のリアクティブな表示のみが必要な場合は Flow として、外部に公開することができます。
次のようにまとめることができます。
package kotlinx.coroutines.flow
interface StateFlow<T> : Flow<T> {
val value: T // always availabe, reading it never fails
}
interface MutableStateFlow<T> : StateFlow<T> {
override var value: T // can read & write value
}
fun <T> MutableStateFlow(value: T): MutableStateFlow<T> // constructor fun
よって、以下、ありがちな記述。(ないか。)
var counter = _counter // NG
val counter = _counter // NG
val counter: MutableStateFlow<Int> = _counter // NG
val counter: StateFlow<Int> = _counter // NG
val counter get() = _counter // NG
val counter: MutableStateFlow<Int> get() = _counter // NG
開発者の間でも、好き嫌いはあるようですが、以下の2パターンが良さげ。Read Only であることが大事。
val counter: StateFlow<Int> get() = _counter // OK
val counter = _counter.asStateFlow() // OK
よって、
class CounterModel {
private val _counter = MutableStateFlow(0)
val counter = _counter.asStateFlow()
fun inc() {
_counter.update { count -> count + 1 }
}
}
最近の言語の仕様は、オフィシャルドキュメントでは分かりずらいポリシーが多くあるように思います。
👉 【MVVM】 ViewModel の_プロパティ記述
👉 【MVVM】 Kotlin Flow で使える5つの利用パターン
👉 StateFlow は distinctUtilChanged 不要