#ViewModelとは?
ViewModelとは、UI関連のデータを保存し管理してくれるクラスです。分かりやすい活用方法でいうと、画面のローテーションをしてもUIを保持してくれたりします。ローテーションに対してUIを保存する方法として、onSaveInstanceState()
メソッドをアクティビティのライフサイクルに組み込むという手がありますが、複雑なデータは保持できない+ライフサイクルを考えなければならないという点で、リスクがあります。そこで、ViewModelが大活躍します。以下の図を見てください。
この図は、ViewModelとActicvityのライフサイクルを表したものです。左がActivity、右がViewModelとなっています。ぱっと見で分かるように、ViewModelにはほぼライフサイクルにおける過程が存在しません。Activityが完全に破棄される(別のアプリに切り替えたり)ときにonClearedが呼ばれるだけです。したがって、いくら画面を回転させてActivityが再生成されようが、ViewModelはそのデータを保持し続けてくれるのです。
もう一つのViewModelのメリットとして、アクティビティやフラグメントが行っていた非同期呼び出しにおけるメンテナンスを容易にしてくれる事が挙げられます。先述したように、ViewModelのライフサイクルは非常にシンプルなので、onDestroy
でいちいち通信をキャンセルさせるなどといったリソースの無駄を排除できます。
以上二つの点がViewModelの主なメリットと役割です。UIに関わるロジックをまとめて管理して複雑さの軽減と効率性の向上を図りましょう。
#LiveDataとは?
ライフサイクルに応じて、データを監視することが出来るクラスです。ActivityやFragmentがアクティブであるときに更新があったデータに対して、自動的に更新を行ってくれます。LiveDataの説明としては以上の通りですが、これではあまり理解が出来ないと思うのでいくつかあるメリットを紹介していきます。
まず、先ほど示唆したようにUI をデータの状態と一致させてくれます。これによって、監視対象にしたデータはアプリのデータが変更されるたびに UI を更新するのではなく、変化が生じるたびに UI を更新できます。言い換えると、能動的にUIを更新していたところを、受動的に更新してくれるということです。また、それに伴ってデータを常に最新にしてくれます。
次に、手動でライフサイクルを処理する必要を省いてくれます。これは、LiveDataが自動的に関連するライフサイクルの状態を認識してくれるためです。ViewModelで例に挙げたように、ローテーションでもデータを保持してくれたりします。それと同時に、メモリリークが発生しません。関連付けているライフサイクルが破壊されたら、それに連動してデータを自動的にクリーンアップしてくれます。
このように、LiveDataも煩わしい処理を自動でこなしてくれます。
#ViewModelとLiveData
ViewModelとLiveDataのそれぞれについて、↑のように説明したわけですが、どちらも同じようなメリットを持っていて、いまいち違いが判らないと思います。利点だけを見れば確かに似通うんですが、この二つはそもそも使われ方が異なります。基本的に、この二つはセットで使われますが、ViewModelはUIに関するロジックを入れる箱で、LiveDataはその中のデータ一つ一つの監視を担います。
この二つを使うのは非常に簡単です。以下にその例を示します。
class Hoge : ViewModel() {
private var fuga: LiveData<String>
}
このように、ViewModelクラスを拡張した箱を作って、LiveDataをインスタンス化して各データの監視を行う場所を作ります。今回はHogeクラスにはfugaしか格納されていませんが、ViewModelを拡張するクラスは基本的にUIに関わるロジックしか入れないことになっています。これは、ViewModelでクラスごとに機能の住み分けを徹底するためです。具体的にはMVVMという設計方針が関係します。
次に、MainActivityでfugaを監視対象にします。
private val hoge : Hoge by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
hoge.fuga.observe(this, Observer { it -> foo = it })
}
hogeというViewModelを拡張したHogeクラスのインスタンスを作り、onCreate内でfugaの具体的な内容(foo)を指定してデータをセットします。observeメソッドはその名の通り、引数を監視対象にします。
これで、fugaは先述したようなViewModelとLiveDataの恩恵を受けれるようなプロパティになりました。これだけで様々な手間が省けるのは非常に楽です。
#ViewModelとLiveDataの実装
最後に、この二つを使うためにbuild.gradle(app)ファイルで必要な実装をしましょう。ライフサイクル対応コンポートの中から、ViewModelとLiveDataだけを実装します。現在の最新版は2.2.0です。
dependencies {
def lifecycle_version = "2.2.0"
// ViewModel
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
// LiveData
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
}
##おわり
今回は備忘録的な意味もかねて記事を書きました。まだ不透明な部分もあるので、多少誤りがあると思われますがご了承ください。今回は公式リファレンスのViewModelとLiveDataのページを主に参照しました。