0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

viewModelScopeに置くべき処理

0
Posted at

概要

viewModelScopeは、画面のための処理を実行する場所です。画面表示やユーザー操作に応じた処理のように、画面が閉じたら止まっても問題ないものは、viewModelScopeに置くのが自然です。

一方で、画面の外でも効いていてほしい処理や、途中で止まると困る処理は注意が必要です。そうした処理までviewModelScopeに載せると、起動元がたまたまViewModelだったというだけで、画面破棄に処理の寿命が引きずられてしまいます。

良い例

  • 画面表示に必要なデータ取得。(画面内に影響が閉じているので、キャンセルされても問題ない)
class UserViewModel(
    private val repository: UserRepository
) : ViewModel() {

    fun loadUser(userId: String) {
        viewModelScope.launch {
            val user = repository.fetchUser(userId)
            // UI state を更新
        }
    }
}

注意が必要な例

  • アプリ全体で使う同期処理を特定画面のViewModelから直接起動する場合
class SomeViewModel : ViewModel() {

    fun syncSharedState() {
        viewModelScope.launch {
            sharedStateSynchronizer.sync()
        }
    }
}

このsyncSharedState()が単なる表示更新のためではなく、ログイン状態に応じた共通データの再同期、複数画面から参照されるキャッシュの整合、未送信データの反映など、アプリ全体で前提となる状態を更新する処理だとします。

その場合、この処理は「この画面が表示されている間だけ生きていればよい仕事」ではありません。にもかかわらずviewModelScopeで起動すると、その画面が閉じられた時点で処理もキャンセルされます。

問題なのは、処理が途中で止まること自体ではなく、「途中で止まってよい性質の仕事なのか」が画面の寿命で決まってしまうことです。本来は画面の表示有無と無関係に完了してほしい同期処理なのに、たまたま起動元がViewModelだったために、画面破棄で止まる設計になってしまいます。

つまり、このケースで確認すべきなのは、syncSharedState()がUI Stateを更新するための補助処理なのか、それともアプリ全体の整合性を保つ責務を持つ処理なのか、という点です。後者であれば、特定画面のViewModelに寿命を委ねるのは適切でなく、画面の破棄とは独立した実行基盤で扱うべきです。

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?