Android - ViewModelを生成する方法

ViewModelはAndroid Lifecycle awareオブジェクトで、Lifecycleを考慮してUIデータを保存および管理するように設計されています。そのため、ViewModelオブジェクトはViewModelProviderを介して生成され、直接コンストラクタを呼び出すことによって生成されません。

ViewModelのコンストラクタの引数があるかどうかによって生成方法が異なります。

  • ViewModelのコンストラクタに引数がない場合:ViewModelProviderでVidwModelオブジェクトを作成できます。
  • ViewModelのコンストラクタに引数がある場合:ViewModelProvider.Factoryクラスを実装すると、ViewModelProviderコンストラクタに引数を渡してオブジェクトを生成できます。

引数がない場合は、ViewModelProviderだけでオブジェクトを生成することができますが、引数がある場合は、Factoryクラスをさらに実装して、どの引数をコンストラクタに渡すかをViewModelProviderに知らせる必要があります。

例を通して詳しく学びましょう。

完全なコードは[GitHub - ViewModelFactorySample]GitHub - ViewModelFactorySampleに置いたので、必要に応じて参照してください。

1. 引数なしの ViewModel オブジェクトの作成

以下のクラスは引数のないViewModelクラスです。

class MainActivityViewModel : ViewModel() {
    val result = MutableLiveData<String>("init value")
}

Activityでは、ViewModelProviderを使用して次のようにViewModelオブジェクトを作成できます。

val viewModel = ViewModelProvider(this).get(MainActivityViewModel::class.java)

ViewModelProvider(this)では、thisはViewModelStoreOwnerを意味します。 ActivityがViewModelStoreOwnerインタフェースを実装しているので、Activityでthisを使用してください。

2. 引数を持つViewModelオブジェクトの作成

次のクラスは、MyRepositoryオブジェクトを引数として受け取るViewModelクラスです。

class FirstActivityViewModel(
    private val repository: MyRepository
) : ViewModel() {

    val result = MutableLiveData<String>("init value")

    fun reloadResults() {
        result.value = repository.getResult()
    }
}

Factory classの実装

ViewModelProviderは、ViewModelを作成するときにどのオブジェクトを引数として渡すべきかわからないので、以下のFactoryクラスを定義してどの引数をコンストラクタに渡すかを定義する必要があります。

class ViewModelFactory(private val repository: MyRepository)
    : ViewModelProvider.Factory {

    override fun <T : ViewModel?> create(modelClass: Class<T>): T {
        if (modelClass.isAssignableFrom(FirstActivityViewModel::class.java)) {
            @Suppress("UNCHECKED_CAST")
            return FirstActivityViewModel(repository) as T
        }
        throw IllegalArgumentException("Unknown ViewModel class")
    }
}

ViewModelの生成

ViewModel を生成するときは、以下のようにまず Factory オブジェクトを生成します。そして、ViewModelProviderにFactoryを渡してViewModelを作成します。 ViewModelProvider は内部的に上記で実装した Factory の create() メソッドを呼び出して引数を持つ ViewModel を生成します。

val repository = MyRepository()
val viewModelFactory = ViewModelFactory(repository)

val viewModel = ViewModelProvider(this, viewModelFactory).get(FirstActivityViewModel::class.java)

3. 引数のない AndroidViewModel オブジェクトの作成

AndroidViewModelはViewModelですが、AppのContext情報を知っているViewModelです。 AndroidViewModelオブジェクトもViewModelProviderを介して作成する必要があります。

以下は、単純な型のAndroidViewModelクラスです。

class SecondActivityViewModel(application: Application)
    : AndroidViewModel(application) {

}

次のように、ViewModelProviderでViewModelオブジェクトを作成できます。 ViewModelProvider の引数として AndroidViewModelFactory オブジェクトを一緒に渡します。

val viewModel = ViewModelProvider(this, ViewModelProvider.AndroidViewModelFactory(application))
        .get(SecondActivityViewModel::class.java)

4. 引数を持つ AndroidViewModel オブジェクトの作成

以下は、MyRepositoryオブジェクトを引数として受け取るAndroidViewModelクラスです。

class ThirdActivityViewModel(
    application: Application, private val repository: MyRepository
) : AndroidViewModel(application) {

}

Factory classの実装

上記で実装した Factory クラスのように、Application と MyRepository オブジェクトを ApplicationViewModel のコンストラクタに渡します。

class ViewModelFactory(private val application: Application, private val repository: MyRepository)
    : ViewModelProvider.Factory {

    override fun <T : ViewModel?> create(modelClass: Class<T>): T {
        if (modelClass.isAssignableFrom(ThirdActivityViewModel::class.java)) {
            @Suppress("UNCHECKED_CAST")
            return ThirdActivityViewModel(application, repository) as T
        }
        throw IllegalArgumentException("Unknown ViewModel class")
    }
}

ViewModelの生成

ApplicationViewModel も、次のように Factory オブジェクトを ViewModelProvider に渡して ViewModel オブジェクトを作成します。

val repository = MyRepository()
val viewModelFactory = ViewModelFactory(application, repository)

val viewModel = ViewModelProvider(this, viewModelFactory)
        .get(ThirdActivityViewModel::class.java)

References

codechachaCopyright ©2019 codechacha