🐡
SharedFlowを使って複数画面で値を共有する
Android開発をしていると複数画面で値を共有したい場合があります。
例えば以下のように、画面Aで表示されているテキストを画面Bで編集できるようなケースです。
画面Bでテキストを編集すると、画面Aに反映されるという仕様です。
業務でこのようなケースに遭遇した場合に、適切な実装方法が分からず、共有するViewModelを作成して、そこに共通のリソースを持たせる作りにしたのですが、以下のような扱いづらさがありました。
- 共有のViewModelに持たせているリソースを各画面のViewModelで処理したい場合にややこしくなる
- 1画面に対応するViewModelが複数あることで見通しが悪くなる
画面A

画面B

そこで、SharedFlowを利用した実装方法だと、上記の問題が解決されていそうなので、サンプルコードを書いてまとめておきます。
登場人物は、以下の3人です。
- SharedFlow (ShareUiState.kt)
- SharedFlowに対してデータを出力するEmitter (SubViewModel.kt)
- SharedFlowから流れてくるデータを受け取るSubscriber (HomeViewModel.kt)
ShareUiState.kt
- 共有するリソースを
ShareUiStateクラスとして作成 -
MutableSharedFlowのコンストラクタに渡すreplyは1とします。-
replyはSubscriberがsubscribeしている時に流れてくるデータの数です。デフォルト値は0なのでこのままだと流れてきません。
-
-
MutableSharedFlow<T>.emit(value: T)を呼び出すことで、データをFlowに出力する事ができます
class ShareUiState {
private val _shareText: MutableSharedFlow<String> = MutableSharedFlow(1)
val shareText: SharedFlow<String> = _shareText
suspend fun send(value: String) {
_shareText.emit(value)
}
}
HomeViewModel.kt
- 画面Aに対応するViewModelであり、FlowをSubscribeするSubscriberです。
-
shareUiState.shareText.collect{}でSharedFlowからデータを受け取り、uiStateを更新します。
class HomeViewModel(
private val shareUiState: ShareUiState
): ViewModel() {
private val _uiState: MutableStateFlow<HomeUiState> = MutableStateFlow(getInitialUiState())
val uiState: StateFlow<HomeUiState> = _uiState
init {
listenUpdate()
}
private fun listenUpdate() {
viewModelScope.launch {
shareUiState.shareText.collect { value ->
_uiState.value = _uiState.value.copy(text = value)
}
}
}
}
SubViewModel.kt
- 画面Bに対応するViewModelであり、Flowに対してEmitするEmitterです。
- ユーザーイベントにより渡されてくるテキストをSharedFlowにEmitします。
class SubViewModel(
private val shareUiState: ShareUiState
): ViewModel() {
private val _uiState: MutableStateFlow<SubUiState> = MutableStateFlow(getInitialUiState())
val uiSate: StateFlow<SubUiState> = _uiState
fun onTextChange(new: String) {
viewModelScope.launch {
_uiState.value = _uiState.value.copy(text = new)
shareUiState.send(new)
}
}
}
Discussion