SharedFlowの使い所

2 min読了の目安(約2200字TECH技術記事

SharedFlowを使ってしっくりきたので紹介です。

画面構成など


プロフィール画面
こちらは「おいしい健康」Android版のプロフィール画面です。
この画面を開く時にAPIから情報を取得してセットし編集が可能です。
「活動量」をタップすると↓の活動量選択画面に遷移します。


おいしい健康 活動量選択画面
こちらはプロフィール画面で表示されてる活動量が初期値としてセットされており、
自分で変更が可能です。

こういった構成の画面を作る場合

  • SharedViewModelでデータを共有
  • Roomでデータ管理
  • SharedPreferencesなどで管理

などの方法がありますが、

  • SharedViewModelだと各画面の処理も入れたくなって後から辛くなる事がある
    ※今回の例だとプロフィール画面と活動量選択画面それぞれの処理をShareするViewModelに書いてしまい後から見直した時にどの画面の処理か分からなくなってしまう(画面のViewModelと共有する情報を別クラスで管理すると情報を使いつつ処理したい時に辛かったり)
  • Roomだと大げさでちょっと工数的に面倒な事がある
  • SharedPreferencesだと型に制限がかかるから辛い時がある
    などのデメリットもあります。

そこでSharedFlowを使った方法を紹介です。

SharedFlowの準備

class Share {
    private val _testFlow = MutableSharedFlow<String>(1)
    val testFlow: SharedFlow<String> = _testFlow
    suspend fun testSend(args: String) = _testFlow.emit(args)
}

MutableSharedFlowのreplay数は1以上で作ります。

これはプロフィール画面でemit後に活動量画面で購読を開始した時にデータを取得できるようにするためです。

プロフィール画面のViewModel

private val share: Share by inject()
val input = share.testFlow.asLiveData()

init {
    request.onEach {
        share.testSend(it)
    }.launchIn(viewModelScope)
}

画面の表示はSharedFlowの値を元に表示します。
今回はasLiveDataしてますが、MutableLiveDataを宣言してpostしたりしてもいいです。

活動量選択画面

ViewModel

private val share: Share by inject()
val selected = share.testFlow.asLiveData()

init {
    request.onEach {
        share.testSend(it)
    }.launchIn(viewModelScope)
}

こちらはプロフィール画面と同様にSharedFlowを購読して初期選択の値をセットします。

Fragment

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    binding.lifecycleOwner = viewLifecycleOwner
    binding.viewModel = viewModel

    binding.button.setOnClickListener {
        viewModel.viewModelScope.launch { 
            share.testSend(viewModel.select)
        }
        findNavController().popBackStack()
    }
}

決定ボタンを押したらSharedFlowに選択した値をemitします。
こうする事でプロフィール画面のViewModelで購読している値も変更されます。
※ViewModelScopeを使っているのはemitと同時にプロフィール画面に戻るのでViewLifecycleScopeを使うより安全かなと思ってやってます。
→作りとしてどうなんでしょう???

結論

SharedFlowを使うと欲しい場所で好きに購読可能なうえ、型も自由にできるので個人的には最高です。
ViewModelも汚れにくいし便利だと思いませんか?