AndroidでFlow<T>
を扱う際の小ネタです。
前置き
Android+KotlinでStateFlow<T>
やSharedFlow<T>
などをLiveData<T>
代わりに利用する際は、
主にActivity
/Fragment
上でlifecycleScope.launchWhenStarted {}
などを使ってcollect {}
を実行することが多いと思います。
その際、LiveData<T>
に比べてコルーチンスコープを開始する関係上ネストが一段深くなってしまいます。
Activity
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
lifecycleScope.launchWhenStarted {
viewModel.flow.collect {
binding.textView.text = it
}
}
}
いくつもcollect
が並ぶとLiveData<T>
に比べて微妙に可読性が下がるのでネストが深くならないように簡単に対策してみます。
Flow<T>
の拡張関数を作って対処する
下記のような拡張関数を用意して、launch
関数でネストさせなくてもcollect
出来るようにしてみます。
FlowCollector.kt
inline fun <T> Flow<T>.collectWhenCreated(lifecycleOwner: LifecycleOwner, crossinline action: suspend (value: T) -> Unit): Job {
return lifecycleOwner.lifecycleScope.launchWhenCreated {
collect(action)
}
}
inline fun <T> Flow<T>.collectWhenStarted(lifecycleOwner: LifecycleOwner, crossinline action: suspend (value: T) -> Unit): Job {
return lifecycleOwner.lifecycleScope.launchWhenStarted {
collect(action)
}
}
inline fun <T> Flow<T>.collectWhenResumed(lifecycleOwner: LifecycleOwner, crossinline action: suspend (value: T) -> Unit): Job {
return lifecycleOwner.lifecycleScope.launchWhenResumed {
collect(action)
}
}
launchWhenStarted
+collect
を置き換える
先程の拡張関数を使うと下記のように表すことができます。
一段ネストが減りましたね!
Activity
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
viewModel.flow.collectWhenStarted(this) {
binding.textView.text = it
}
}
Fragment
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel.flow.collectWhenStarted(viewLifecycleOwner) {
binding.textView.text = it
}
}
通常のFlow<T>
の扱いと同様に、FragmentでViewの更新をする場合は引数にthis
ではなくviewLifecycleOwner
を指定する必要があるのでご注意下さい。
たったこれだけですが地味に便利なので試してみて下さい