ViewModel、ViewModelProviderについて調べてみた(Android)

Keisuke Kawajiri
Dec 27, 2019 · 6 min read

先日、URLメモの動作確認をしていたのですが、画面回転後、メモの再検索が実行され、スクロールが戻る問題に気付きました。

修正前の動作

期待していた動作は、

  • 画面回転後、画面回転前のメモデータが表示されていること。
  • 画面回転後、画面スクロールの状態を保持されていること。

でした。

ViewModelを使用すると、期待する動作が実現できると想定していたのですが、何故だろうという感じでした。
結局、原因はViewModelProviderを利用して、画面に対応するViewModelを生成 & 取得していなかったからでした。実装を間違えてました😞

修正後の動作

ViewModelProviderを利用すると期待通り動作したのですが、せっかくなので、ViewModelProviderの動作について少し調べてみたので、紹介したいと思います。

ViewModelProviderは、ライフサイクルを考慮して所望のViewModelを提供するクラスです。ViewModelProviderは次のコンストラクタを使って、たいてい生成すると思います。

public ViewModelProvider (ViewModelStoreOwner owner, 
ViewModelProvider.Factory factory)

引数について説明します。

  • ViewModelStoreOwner owner
    ViewModelStoreを返すインタフェースです。ViewModelStoreOwnerは、FragmentやAppCompatActivityで実装されているので、通常はthisを引数として渡します。
    ここで、ViewModelStoreはViewModelを保持するクラスです。
    ViewModelStoreは、ViewModelStoreOwner#getViewModelStoreの実行時にActivityFragmentに対応して生成されており、既にViewModelStoreが生成されている場合は、それを返却するよう実装されています。
  • ViewModelProvider.Factory factory
    引数のViewModelクラスのインスタンスを生成するための、factoryです。
    生成するViewModelのコンストラクタに引数がなければ、
    ViewModelProvider.NewInstanceFactoryを、ViewModelがAndroidViewModelを継承している場合は、ViewModelProvider.AndroidViewModelFactoryが使えます。
    また、自分で実装したViewModelProvider.Factoryを指定することもできます。手抜きの例ですが、次のように実装できます。

次にViewModelの初期化ですが、ViewModelProviderを利用して次のように行います。

val viewModel = ViewModelProvider(this, yourFactory)
.get(YourViewModel::class.java)

ViewModelProvider#getが実行されると、引数で指定されたクラスと同じ型のViewModelが、ViewModelStoreに存在するかどうかで、次の動作をします。

  • 存在する場合
    ViewModelStoreで保持していたViewModelを返します。
  • 存在しない場合
    引数で指定されたViewModelのインスタンスをViewModelProviderのfactoryにより生成して、それを返します。また、ViewModelStoreに生成したViewModelを保存します。

ということで、あるViewModelに対して、初めてViewModelProvider#getを実行すると、そのViewModelをViewModelStoreに保存します。
そして、例えば画面回転により再度、ViewModelProvider#getが実行されると、すでにViewModelStoreにあるViewModelを返します。これにより、ViewModelのデータの引継ぎが可能になっています。
但し、ViewModelStoreはViewModelStoreOwnerのライフサイクルに従うので、例えば、ViewModelStoreOwnerがFragmentの場合、バックボタンなどを押して、そのFragmentが破棄されればViewModelStoreもクリアされます(この辺りかと)。他にも、自分でViewModelStore#clearを実行すれば、クリアすることはできます。

今回は、ViewModel、ViewModelProviderについて調べたことを紹介しました。調べる際、ソースコードを色々と眺めてみましたが、さわりぐらいしか理解できませんでした。
下記の公式のページが参考になります。

URL Memo

URLメモ(Androidアプリ)の開発記録です。

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store