ViewModelの作り方
次に、ViewModelの作り方を紹介していきます。
ViewModelを継承
ViewModelは一つのクラスとして定義します。その際、androidx.lifecycle.ViewModelクラスを継承します。そして、先述のように、ViewModelはアクティビティに寄り添うように存在することから、原則、一つのアクティビティクラスに対して一つ作成します。
例えば、MainActivity用のViewModelは、MainViewModelとするように、対応関係がわかるようにしておきます。
クラスメンバはUIのデータ処理を記述
ViewModelクラスのメンバとしては、相方となるアクティビティに必要なデータを踏まえた上で、以下のものを定義します。
- UIで扱うデータのprivateフィールド
- 上記フィールドのセッタとゲッタ(アクセサメソッド)
- UIの入出力に必要なデータをやり取りするためのメソッド
例えば、前節で紹介した足し算アプリのMainActivity用のViewModelであるMainViewModelは、Javaではリスト1のようなコードとなります。
public class MainViewModel extends ViewModel {
private int _num1 = 0; // (1)
private int _num2 = 0; // (2)
public int getAns() { // (3)
return _num1 + _num2;
}
public String getAnsStr() { // (4)
String ansStr = "";
if(getAns() != 0) {
ansStr = String.valueOf(getAns());
}
return ansStr;
}
public String getNum1Str() { // (5)
String num1Str = "";
if(_num1 != 0) {
num1Str = String.valueOf(_num1);
}
return num1Str;
}
public void setNum1Str(String num1Str) { // (6)
if(num1Str.equals("")) {
_num1 = 0;
}
else {
_num1 = Integer.parseInt(num1Str);
}
}
public String getNum2Str() { // (7)
String num2Str = "";
if(_num2 != 0) {
num2Str = String.valueOf(_num2);
}
return num2Str;
}
public void setNum2Str(String num2Str) { // (8)
if(num2Str.equals("")) {
_num2 = 0;
}
else {
_num2 = Integer.parseInt(num2Str);
}
}
public int getNum1() { // (9)
return _num1;
}
public void setNum1(int num1) { // (9)
_num1 = num1;
}
public int getNum2() { // (9)
return _num2;
}
public void setNum2(int num2) { // (9)
_num2 = num2;
}
}
足し算アプリでは、入力された2個の数値が、フィールドとして定義される必要があります。これらを定義しているのが(1)の_num1と(2)の_num2です。そして、それぞれのアクセサメソッドが(9)です。さらに、これらのフィールドをもとに足し算処理を行なっているのが(3)です。
ただし、EditTextにしても、TextViewにしても、実際に画面とのデータのやり取りは文字列です。そのため、文字列と整数値とのやり取りを可能にしているメソッドが(4)〜(8)です。(4)が足し算結果を文字列に変換しているメソッドです。
(5)と(6)が_num1に対しての文字列と整数値の相互変換、(7)と(8)が_num2に対しての文字列と整数値の相互変換のメソッドです。それぞれのメソッドにおいて、文字列が空文字("")の場合や整数値が0の場合などの処理も含め、問題なくデータを受け取ったり表示したりできるようにしています。
Kotlinはプロパティを利用
Kotlinコードでも、ViewModelは同様の作りとなり、リスト2のようになります。
class MainViewModel : ViewModel() {
var num1 = 0 // (1)
var num2 = 0 // (2)
fun getAns(): Int { // (3)
return num1 + num2;
}
fun getAnsStr(): String { // (4)
var ansStr = ""
if(getAns() != 0) {
ansStr = getAns().toString()
}
return ansStr
}
fun getNum1Str(): String { // (5)
var num1Str = ""
if(num1 != 0) {
num1Str = num1.toString()
}
return num1Str
}
fun setNum1Str(num1Str: String) { // (6)
if(num1Str.equals("")) {
num1 = 0
}
else {
num1 = num1Str.toInt()
}
}
fun getNum2Str(): String { // (7)
var num2Str = ""
if(num2 != 0) {
num2Str = num2.toString()
}
return num2Str
}
fun setNum2Str(num2Str: String) { // (8)
if(num2Str.equals("")) {
num2 = 0
}
else {
num2 = num2Str.toInt()
}
}
}
リスト2のJavaコードをそのままKotlinコードに置き換えたような内容になっていますが、1点大きく違うのが、アクセサメソッドがないことです。Kotlinの場合は、(1)と(2)のようにプロパティを定義するだけで、自動的にアクセサメソッド経由でのデータのやり取りとなるからです。
他のコードは、Javaコードと同じく、(3)が足し算処理を行うメソッドであり、(4)がその結果の文字列を取得するメソッドです。(5)と(6)がnum1に対しての文字列と整数値の相互変換メソッド、(7)と(8)がnum2に対しての文字列と整数値の相互変換メソッドです。
このように、ViewModelを定義すると、UIに必要なデータとその処理が、全てViewModelクラスに記述されることになります。
