ViewModelの利用
では、これらのViewModelをアクティビティで利用するコードを見ていきましょう。
ViewModelはフィールドで定義しonCreate()で用意
先述のように、図3を見ると、ViewModelは、その相方となるアクティビティで生成されると、その後はアクティビティが消滅するまで存在することになります。そこで、アクティビティでは、相方となるViewModelクラスをフィールドで用意しておき、onCreate()で実際のオブジェクトを用意します。これは、例えば、Javaではリスト3のようなコードになります。
public class MainActivity extends AppCompatActivity { private MainViewModel _mainViewModel; // (1) @Override protected void onCreate(Bundle savedInstanceState) { : ViewModelProvider provider = new ViewModelProvider(MainActivity.this); // (2) _mainViewModel = provider.get(MainViewModel.class); // (3) EditText etNum1 = findViewById(R.id.etNum1); // (4) etNum1.setText(_mainViewModel.getNum1Str()); // (4) EditText etNum2 = findViewById(R.id.etNum2); // (4) etNum2.setText(_mainViewModel.getNum2Str()); // (4) TextView tvAnswer = findViewById(R.id.tvAnswer); // (4) tvAnswer.setText(_mainViewModel.getAnsStr()); // (4) } : }
リスト3の(1)が、リスト1のMainViewModelをフィールドとして定義しているコードです。そして、実際にそのオブジェクトを取得しているのが、(2)と(3)です。ViewModelオブジェクトは、そのクラスを直接newするのではなく、まず、(2)のようにViewModelProviderをnewします。その際、引数に、コンテキストとしてアクティビティオブジェクトを渡します。このViewModelProviderにアクティビティオブジェクトを渡すことで、生成されるViewModelとこのアクティビティがペアになります。
その後、newされたViewModelProviderオブジェクトのget()メソッドを実行することで、ViewModelオブジェクトを取得します。それが、(3)です。その際、取得するViewModelクラスを渡します。
onCreate()でViewModelのデータと画面部品を紐付ける
ここでひとつ注意点があります。リスト3の(2)と(3)のように生成したViewModelオブジェクトを利用して、同じくonCreate()において画面部品とViewModel内のデータを紐づけておく必要があります。それが(4)です。num1とnum2の値を入力するEditTextに対してそれぞれgetNum1Str()とgetNum2Str()の値を、答え表示TextViewに対してgetAnsStr()の値を設定しています。
その後は、例えば、計算ボタンをクリックした時の処理も、リスト4の(1)と(2)のように単に入力データを_mainViewModelにセットし、(3)のようにgetAnsStr()をtvAnswerにセットするだけで、問題なく表示されるようになります。しかも、画面を回転させても、図4のように値を保持したままとなります。
public void onBtCalcClick(View view) { EditText etNum1 = findViewById(R.id.etNum1); String num1Str = etNum1.getText().toString(); _mainViewModel.setNum1Str(num1Str); // (1) EditText etNum2 = findViewById(R.id.etNum2); String num2Str = etNum2.getText().toString(); _mainViewModel.setNum2Str(num2Str); // (2) TextView tvAnswer = findViewById(R.id.tvAnswer); tvAnswer.setText(_mainViewModel.getAnsStr()); // (3) }
KotlinではviewModels()を利用
では、KotlinコードでViewModelを利用する場合は、アクティビティにはどのようなコードを書けばいいのかというと、Javaコードと同じようにViewModelProviderを利用したコードでも問題なく動作します。すなわち、リスト3の(2)と(3)をKotlinコードに置き換えたコードです。一方、Kotlinの場合は、リスト5のように、もっと簡潔に記述できます。
class MainActivity : AppCompatActivity() { private val _mainViewModel by viewModels<MainViewModel>() // (1) override fun onCreate(savedInstanceState: Bundle?) { : val etNum1 = findViewById<EditText>(R.id.etNum1) // (2) etNum1.setText(_mainViewModel.getNum1Str()) // (2) : // (2) } : }
Kotlinでは、ViewModelオブジェクトを簡単に取得するための記述として、以下が用意されています。
by viewModels<…>()
リスト5の(1)のように、プロパティとしてViewModelオブジェクトを定義しておき、その続きに、上記コードを記述するだけで、自動的にViewModelオブジェクトを生成してくれます。その際、どのクラスのViewModelを生成するのかを、ジェネリクスとして型指定します。
ただし、このviewModels()を利用するためには、activity-ktxライブラリを追加しておく必要があります。これは、build.gradle(Module)ファイルのdependenciesに以下の1行を追加することで可能となります。
implementation "androidx.activity:activity-ktx:1.5.1"
なお、「1.5.1」というバージョンは、原稿執筆時点での最新安定版です。1.6.0がリリースされているという警告が表示されますが、まだRC版ですので、現時点では1.5.1がおすすめです。
追加後は、画面右上に表示される[Sync Now]をクリックして、再ビルドを行うことを忘れないでください(図5)。
ところで、リスト5の(2)は、リスト3の(4)のJavaコードをそのままKotlinコードに置き換えたものです。Kotlinでも、onCreate()で紐付けを行っておくことを忘れないようにしてください。そのようにしておくだけで、計算ボタンの処理については、リスト4のonBtCalcClick()メソッドのコードを、そのままKotlinに置き換えたコードで問題なく動作します。
まとめ
Android Jetpackについて紹介していく本連載の第1回は、いかがでしたでしょうか。初回を飾るテーマは、UIに必要なデータ処理を担うViewModelを紹介しました。ViewModelを導入することで、アクティビティは本来のUIの処理に集中できるようになります。
次回は、データベース処理を容易に実装できるライブラリであるRoomを紹介します。