2020/03/11
by ViewModels() を使って ViewModel を取得する方法
以前は以下のように [ViewModelProviders](https://developer.android.com/reference/androidx/lifecycle/ViewModelProviders) を使用して [ViewModel](https://developer.android.com/reference/androidx/lifecycle/ViewModel) を取得していましたが、この方法は Deprecated になりました。 ```kotlin val myViewModel = ViewModelProviders.of(this).get(MyViewModel::class.java) ``` ドキュメントを見てみると、代わりに kotlin の委譲 `by viewModels()`、もしくは `ViewModelProvider` ### 依存関係 `viewModels` は `fragment-ktx` というパッケージ内に入っているので 、これを `implementation` に加えます。 ```groovy `title: "build.gradle in app"; dependencies { ... implementation 'androidx.fragment:fragment-ktx:1.2.2' } ``` ### コンパイラのバージョンを 1.8 互換に 環境によっては以下のように、JVM のターゲットバージョンが合ってない旨のエラーがでてしまいます。 "Cannot inline bytecode built with JVM target 1.8 into bytecode that is being built with JVM target 1.6. Please specify proper '-jvm-target' option" これを解決するには、以下のように `build.gradle` に追記します。 ```groovy `title: "build.gradle in app"; android { ... compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } kotlinOptions { jvmTarget = JavaVersion.VERSION_1_8.toString() } } ``` この問題、`viewModels()` に限ったことではなく、新しめの kotlin ライブラリを使おうとすると起こります。 > 参考 > > [android - Cannot inline bytecode built with JVM target 1.8 into bytecode that is being built with JVM target 1.6 - Stack Overflow](https://stackoverflow.com/a/56996020) ### 基本の使い方 以下のように使用します。 ```kotlin class MainActivity : AppCompatActivity() { // lazy なので最初に使用する時に初期化される private val myViewModel by viewModels<MyViewModel>() fun something() { myViewModel.users.observe(this, Observer { // Do something }) } } ``` ### Factory 指定 Factory を指定した初期化の方法は以下。 ```kotlin private val myViewModel by viewModels<MyViewModel>{ MyViewModelFactory() } ``` `viewModels` の実装を覗いてみると、以下のようになっています。 `Factory` を返す関数を与えられるようになっているわけですね。 ```kotlin @MainThread inline fun <reified VM : ViewModel> ComponentActivity.viewModels( noinline factoryProducer: (() -> Factory)? = null ): Lazy<VM> { val factoryPromise = factoryProducer ?: { defaultViewModelProviderFactory } return ViewModelLazy(VM::class, { viewModelStore }, factoryPromise) } ``` `ViewModelLazy()` も public なクラスなので、これを直接使えば `ViewModelStoreOwner` (Activity や Fragment 等)を指定できます。 しかし、これは遅延初期化オブジェクト。どのタイミングで呼ばれるかが定かではありません 。 Activity や Fragment 等、ライフサイクルによっては正しく動作しないものを指定すべきではありません。 そういった用途には以下の `ViewModelProvider` を使うのが良いでしょう。 ### 【参考】ViewModelProvider クラスを使う ドキュメントには `by viewModels()` もしくは [ViewModelProvider()](https://developer.android.com/reference/androidx/lifecycle/ViewModelProvider) を使って。とかいてあります。 こちらは、`ViewModelProviders.of()` とほぼ同様なので、簡単に使えるかと思います。 ```kotlin // ViewModelProviders.of(this) とほぼ同じように使える val myViewModel= ViewModelProvider(this).get(MyViewModel::class.java) ```を使ってね。と書いてあります。 ところが、`by viewModels()` はどう使うのかが、何処にも書いてありません 。 そこで、ネットの情報とコードを参考に使ってみました。
0 件のコメント:
コメントを投稿