怠慢プログラマーの備忘録

怠慢でナマケモノなプログラマーの備忘録です。

次世代LiveDataであるKotlin Coroutines StateFlow・SharedFlowについて

Kotlin Coroutines1.3.6で投入されたStateFlow、1.4.0で投入されたSharedFlowに関しての備忘録です。

Flowに関して

Flowに関しては割愛します。

こちらの以下の記事がわかりやすいかと思います。

2020年は脱RxでKotlin Coroutinesに置き換えていく作業を嫌というほどやりました。

qiita.com

SharedFlowとは

Flowに対してホットストリームとなっています。

val mutableSharedFlow = MutableSharedFlow<Int>()

のようにしてSharedFlowを作成します。
Flowとことなり直接値をemit()することができます。(suspend functionの為コルーチンスコープが必要)

また

val mutableSharedFlow = MutableSharedFlow<Int>(replay = 3)

のようにreplayを指定するとlanchする前、直近3件をキャッシュしてくれたりします。

LiveData.setValue()に似たような挙動なので1つ1つデータを流し込んでいく際などはMutableSharedFlow(replay = 1)とかにしておくとよさそうです。

StateFlowとは

状態保持に特化したSharedFlowで内部でもSharedFlowが拡張されているようです。

kotlin.github.io

SharedFlowと異なる点としては初期値が必要でlanchしたタイミングで直近のデータが流れます。

またコルーチンスコープを必要とせず.valueでその当時の値を見れたり設定が可能です。

変更通知を受け取るのに.collectを使用します。ViewModelでStateFlowを定義してActivity/Fragmentで.collectする、みたいなのが一般的な使用方法かと思います。

class HomeViewModel(user: User, private val repository: UserRepository = UserRepository()) : ViewModel() {
    private val _userStateFlow = MutableStateFlow(user)
    val userStateFlow: StateFlow<User> = _userStateFlow

    init {
        viewModelScope.launch {
            repository.fetch.collect { user ->
                _userStateFlow.value = user
            }
        }
    }
}

とあって、

        lifecycleScope.launchWhenStarted {
            viewModel.userStateFlow.collect { user ->
                binding.textView.text = user.name
            }
        }

みたいな感じです。