Android Bindingを使ってみた(1) - タイトルは未定の続きです。
もう少しAndroid Bindingメリットを享受するために、ActivityとViewModelを分離してみます。
目的は「ViewModelをAndroidのクラスに依存しない様にする」です。
その理由は「ViewModelのUnitTestがAndroidの実機やエミュレータなしに行える様になる」ということになります。
最初に
ViewModelにはStringObservable型のメンバやCommandを実装したメンバを移動することになりますが、CommandクラスのInvokeは引数が以下の様になっており、Viewを抱え込んでいます。
public void Invoke(View arg0, Object... arg1) {
つまり、CommandをViewModelに持って行ったとしてもAndroidのクラスへの依存は残ってしまいます。
そこで、PojoViewModelを使用することでこの問題を解消します。
PojoViewModelの概要は以下の通りです*1。
PojoViewModel - android-binding - Pojo (Plain-Old-Java-Object) View Model support
Introduction
序論Currently experimenting Pojo-styled (Plain-Old-Java-Object) View Models.
現在実験中であるPojoスタイルのView Modelです。Such View Models no longer need the Observables nor Commands but simply defined their own binding-interfaces as normal object:
このView ModelはObservablesやCommandsを必要とせず、通常のオブジェクトの様に、シンプルに定義されたバインディング用のインターフェースを必要とします。
- Commands: Plain 'void' Method with No arguments
- Commands:引数や戻り値のないシンプルなメソッド
- Observables: Private fields with public getters and/or setters
- Observables: puulicなセッターやゲッターとprivateなフィールド
The only requirement for the ViewModel is it need to implements the PojoViewModel interface.
ViewModelが必要とする唯一の要件は、PojoViewModelインターフェースを実装することです。
実装の変更方針
いきなりActivityとViewModelに分けると分離作業とPojoViewModelの実装を平行して行うことになり、作業が複雑になります。
今回は一旦ActivityにPojoViewModelを実装し、それからActivityとViewModelに分離することにします。
AndroidBindingSampleActivity
PojoViewModelインターフェースの実装
10行目付近までお決まりの書き方になります。
PojoViewModelをimplementsすれば、大部分をeclipseが実装してくれます。
setBMI
データが変更されたことを通知するためにメンバ変数の更新はsetter経由で更新します。
getBMI
Viewが参照するgetterになります。
onCreate
Binder.setAndBindContentViewする部分が以下の様に変わっています。
Binder.setAndBindContentView(this, R.layout.main, this);
↓
Binder.setAndBindContentView(this, R.layout.main, PojoViewModelWrapper.create(this));
ソース
public class AndroidBindingSampleActivity extends Activity implements PojoViewModel { private PojoViewModelHelper helper = new PojoViewModelHelper(); public PojoViewModelHelper getHelper() { return helper; } public void notifyPropertyChanged(String propertyName) { helper.notifyPropertyChanged(propertyName); } private EditText heightText; private EditText weightText; private double _bmi; public void setBMI(double bmi) { _bmi = bmi; notifyPropertyChanged("BMI"); } public String getBMI() { return "Your BMI is " + String.valueOf(_bmi); } public void Calculate() { double height = Integer.valueOf(heightText.getText().toString()); double weight = Integer.valueOf(weightText.getText().toString()); double bmi = weight / Math.pow(height / 100.0, 2); setBMI(bmi); }; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Binder.init(this.getApplication()); Binder.setAndBindContentView(this, R.layout.main, PojoViewModelWrapper.create(this)); heightText = (EditText) findViewById(R.id.height); weightText = (EditText) findViewById(R.id.weight); } }
レイアウト(View)
ボタン
AndroidBindingSampleActivityのCalculateメソッドにバインドしています。
テキスト
AndroidBindingSampleActivityのgetBMIにバインドされることになります。
ソース(抜粋)
<Button android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="計算" binding:onClick="Calculate" /> <TextView android:id="@+id/buttonCalculateBMI" android:layout_width="fill_parent" android:layout_height="wrap_content" binding:text="BMI" />
おしまい
これでPojoViewModelの実装が終わりました。次はActivityとViewModelの分離を行いたいと思います。
*1:オレオレ意訳なので微妙に間違ってたらごめんなさい