はじめに
つい最近ViewModelを触り始めたのですが、当初は律儀にViewModelProvider(s)を使っていました。
しかし、fragment-ktxを使うことでかなり簡素にViewModelを生成出来たので自分用に纏めておきます。
実装
jvmTargetを1.8に指定し、lifecycle-viewmodel-ktx
とfragment-ktx
を追加する。
android {
kotlinOptions {
jvmTarget = '1.8'
}
}
dependencies {
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0"
implementation "androidx.fragment:fragment-ktx:1.2.3"
}
引数なしの場合
まずは引数なしのViewModelから。
とりあえず引数なしのViewModelを定義する。
initとhelloメソッド呼び出しのタイミングでそれぞれログを出力させる。
class MainViewModel : ViewModel() {
init {
Log.d("MainViewModel", "init")
}
fun hello() {
Log.d("MainViewModel", "hello")
}
}
1行サクッと書くだけでViewModelが取得できる。
class MainActivity : AppCompatActivity() {
private val viewModel: MainViewModel by viewModels() // ← ここ!!
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
viewModel.hello()
}
}
initとhelloメソッド呼び出しのタイミングでそれぞれログが出力されているのがわかる。
2020-03-30 22:48:02.199 3963-3963/com.masaibar.viewmodelsample D/MainViewModel: init
2020-03-30 22:48:02.199 3963-3963/com.masaibar.viewmodelsample D/MainViewModel: hello
引数ありの場合
続いて引数ありの場合、先程のViewModelのコンストラクタをuserId
という引数を受け付けるように変更した。
class MainViewModel(
private val userId: String
) : ViewModel() {
init {
Log.d("MainViewModel", "init, userId: $userId")
}
fun hello() {
Log.d("MainViewModel", "hello, userId: $userId")
}
}
今度は先程のように1行だけサクッとという訳にはいかないが
それでもViewModelProviderクラスを定義しなくてもこのように書くことが出来る。
class MainActivity : AppCompatActivity() {
private val viewModel: MainViewModel by viewModels {
object : ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
@Suppress("UNCHECKED_CAST")
return MainViewModel("masaibar") as T
}
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
viewModel.hello()
}
}
initとhelloメソッド呼び出しのタイミングでそれぞれログが出力されuserId
が渡っていることが確認できる。
2020-03-30 22:58:52.525 4979-4979/? D/MainViewModel: init, userId: masaibar
2020-03-30 22:58:52.525 4979-4979/? D/MainViewModel: hello, userId: masaibar
おわりに
Googleにはもう少しこれを推していって欲しいです。