kotlinのFlowについて自分なりにまとめ
この記事について
Flow
の説明をもっと簡単にできないかなとまとめたものです
プログラムよりFlow
の仕組み等を説明してます
kotlin初心者の自分なりにまとめたもので足りない部分があるかもしれませんがご了承ください
読者対象者
これらを知ってると理解が早くなるかもしれません
- Coroutines
- LiveData
- MVVM
Flowについて
単純にいうと非同期で複数の返り値がくるsuspend関数みたいなもの。同時に複数の場所で値を観測することができる。Coroutinesの仲間。
チャットアプリの例でいうと、サーバーからのチャット更新通知が来たときに各更新処理を行うなど(チャット更新・キャッシュ保存 etc...)
以下にそれっぽいプログラム
// チャット更新通知リスナー的なもの
val chatsListener = ChatsListener()
//チャットFlow
val latestChats: Flow<List<Chat>> = flow {
chatsListener.updateChat { chats ->
//チャット更新時通知を送信
emit(chats)
}
}
...
//ViewModel層で観測
latestChats.collect { chats ->
// ソート処理など
}
...
//View層で観測
latestChats.collect { chats ->
// UI更新処理など
}
ちなみにFlowの由来は水の流れをイメージしたもので、上から流れてくる情報を下へと伝播する様子かららしい
Flowの種類
主に使うFlowは以下のような種類がある
- Flow
- SharedFlow
- StateFlow
StateFlow
はSharedFlow
を扱いやすくした機能制限版と思ってok(詳細は公式)
大きな違いとしてはFlow
は更新後の値を持たず(観測場所への更新通知だけ)、SharedFlow
・StateFlow
は更新後の値を持つ
そのためShareFlow
, StateFlow
はLiveData
に近い(実際に値の更新・取得はvalue
で行える)
LiveDataとの比較
StateFlow
系は非同期処理やDataBindingで使われるLiveData
のほぼ上位互換
LiveDataで不便だった部分がいろいろ直っているので、基本的にLiveDataはStateFlowに置き換えるのが良い
参考URL: livedataとstateflowの違い
自分的大きな利点は
-
NullableだったLiveDataと違い、NonNullで値が観測できる
初期値を設定したLiveDataでもNullチェックしなければいけなかったのでとても楽になった -
オペレーターが多種(map,filterなど)
非同期に受信したデータをfilter等できる関数が揃ってるのでコードが書きやすい
個人的にはVueのcomputed
(他の変更に伴って再計算される変数) みたいな使い方ができるから楽(非同期で変更される複数の情報を組み合わせるなど)
以下プログラム例
...
// ユーザーリスト
const users = ref<Users[]>([])
// ソート済みユーザーリスト
const sortedUsers = computed(()=>{
// (ちなみにこれは最近追加されたTS新ソート関数)
users.toSorted()
})
...
...
// ユーザーリスト
private val _usersStateFlow = MutableStateFlow(ArrayList<User>())
val usersStateFlow = _usersStateFlow.asStateFlow()
// ソート済みユーザーリスト(VueのComputedもどき)
val sortedUsersStateFlow = usersStateFlow.transform{
// ユーザーリスト更新時にソートして通知
emit(it.sortedBy { user -> user.age})
}.stateIn(
// 観測のスコープを設定する(呪文だと思ってよし)
// 詳細:https://android.benigumo.com/20210827/mvvm-kotlin-flow/
viewModelScope,
SharingStarted.WhileSubscribed(5000)
listOf()
)
...
ちなみにcombine()
を使うと複数のFlowの変更通知を受け取った処理もできるので、比較関数変更orユーザーリスト変更時に自動でソートすることもできる
LiveData
だとMediatorLiveData
を使って変更時に更新する手もあるが、変数定義の形で書けてわかりやすいのがとても良い
DataBinding
でもLiveData
の代用としてStateFlow
が利用でき、asLiveData()
でLiveData
を取得することも可能である(Flow側更新時にもちゃんと更新通知される)
さいご
Flowは名前の通り流れるようにかなり柔軟な非同期処理を行えるので活用できるととても便利
基本的にLiveData
はStateFlow
で代用しましょう(LiveDataでできないことがあるというほどではないので、すでにLiveDataだらけとかなら無理に変える必要はなし)
特に複雑な非同期処理が必要なときは開発しやすくなると思います
使い方によっては簡易イベントリスナー(特にViewModelからFragmentへの通信)もできたり、LiveData
よりも非同期処理で多岐に扱えるので知っておくと便利です
Discussion