2
1

UI状態をdata classで管理する時の大体のお決まりっぽいもの

Last updated at Posted at 2024-04-22

概要

AndroidでUI状態を管理するときにいろいろやり方があると思いますが、UiState状態をdata classで定義しておいて使用する方法があると思います。
使用する際に「これどうすれば良いんだっけ?」と思うことがあるのである程度のお決まりみたいなものをまとめておきます。

定義するとき

SampleViewModel.kt
// ViewModelの外に定義しておく
// プロパティ多いようだったら別ファイルにした方が良いかも
data class SampleUiState(
    val message: String = "",
    val loading: Boolean = false,
    val user: User? = null
)

@HiltViewModel
class SampleViewModel @Inject constructor() {
    ....
}

ViewModel内で使うとき

updateとcopyを使っていきます。ただコードが長くなりがちなので、拡張関数を何かしら作っておくと良いかもしれません。
なぜupdateを使うのかというと、スレッドセーフかつアトミック(完全に行われるか全く行われないかのいずれか)な方法だからです。

SampleViewModel.kt
@HiltViewModel
class SampleViewModel @Inject constructor() {

    private val _uiState = MutableStateFlow(SampleUiState())
    val uiState: StateFlow = _uiState.asStateFlow()

    fun getUser() {
        _uiState.update { state ->
            state.copy(
                loading = true
            )
        }
        viewModelScope.launch {
            try {
                val user = userRepository.getUser()
                _uiState.update { state ->
                    state.copy(
                        user = user
                    )
                }
            } catch (e: Exception) {
                _uiState.update { state ->
                    state.copy(
                        message = "error"
                    )
                }
            } finally {
                _uiState.update { state ->
                    state.copy(
                        loading = false
                    )
                }
            }
        }
    }
}

Compose Viewで使うとき

単純にViewModelで個別に値を持っているよりuiStateで持っている方がviewModel.hoge.valueみたいに書かなくて済むのでちょっと楽です。

SampleComposable.kt
@Composable
fun SampleComposable(
    viewModel: SampleViewModel
) {
    // ライフサイクルを考慮する場合はcollectAsStateWithLifecycle()を使った方が良い
    val uiState by viewModel.uiState.collectAsState()

    Text(text = uiState.message)
}

Activityで使うとき

SampleActivity.kt
@AndroidEntryPoint
class SampleActivity : AppCompatActivity() {

    val viewModel: SampleViewModel by viewModels()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        ..
        lifecycleScope.launch {
            // repeatOnLifecycleはライフサイクルに応じてJobを操作してくれる
            repeatOnLifecycle(Lifecycle.State.STARTED) { 
                viewModel.uiState.collect { uiState ->
                    ..
                }
            }
        }
    }
}

まとめ

場合によってベストプラクティスは変わってくるかと思いますが、大体のやり方は似てくるかと思います。
もっと良いやり方があったら適宜追記します。

参考

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1