Android Binding
さて昨日の続きで引き続きAndroid Bindingで遊んでみます。次の題材は電卓アプリです。元ネタはこちら。
Build a simple Android calculator with MVVM (& Android Binding!)
電卓アプリは一般にボタンが多いので、MVC (MVVM) パターンを適用するにはモッテコイの題材ですね。ちなみに見た目はこんな感じです。
まずは計算結果を表示するTextViewから見ていきます。
<!-- 計算結果 --> <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_weight="1" android:textSize="45dp" android:gravity="right|bottom" binding:text="FormattedDisplay" />
バインド先 (FormattedDisplay) はこんな感じ。
// 計算結果表示用プロパティ public final Observable<Double> Display = new Observable<Double>(Double.class, 0d); public final DependentObservable<String> FormattedDisplay = new DependentObservable<String>(String.class, Display) { @Override public String calculateValue(Object... arg0) throws Exception { DecimalFormat format = new DecimalFormat(); format.applyPattern("#.######"); String output = format.format(Display.get()); if(output.length() <= MAXLENGTH) { return output; } format.applyPattern("#.########E00"); return format.format(Display.get()); } };
DependentObservableという新しいオブザーバ (Property) があります。これは上のDisplayプロパティに依存したプロパティであることを意味します。つまりDisplayプロパティに変化があれば、このFormattedDisplayプロパティにもその変更が伝播する、という仕組みです。単純な情報を加工してViewとバインドする際に使われます。まさしくこれがViewModelコンポーネントですね。
次は数字ボタン。レイアウトファイルから。
<Button android:text="7" binding:onClick="Number7" /> <Button android:text="8" binding:onClick="Number8" /> <Button android:text="9" binding:onClick="Number9" /> <!-- などなど -->
そしてバインド先 (Number7, 8, 9, ...) 。
// 数字ボタン用コマンド public NumberCommand Number9 = new NumberCommand(9); public NumberCommand Number8 = new NumberCommand(8); public NumberCommand Number7 = new NumberCommand(7); // などなど // 数字ボタンアクションに対応するコマンドクラス private class NumberCommand extends Command { // CommandはInterfaceじゃない! private int _number = 0; public NumberCommand(int number) { _number = number; } @Override public void Invoke(View arg0, Object... arg1) { addNumber(_number); } }
Commandは以前はインターフェイスだったようですが、現バージョンでは抽象クラスなので注意が必要です。
そして最後に演算ボタンを見てみます。
<Button android:text="/" binding:onClick="Divide" /> <Button android:text="X" binding:onClick="Multiply" /> <Button android:text="-" binding:onClick="Minus" /> <Button android:text="+" binding:onClick="Plus" />
バインド先 (Divide, Multiply, Minus, Plus) はこんな感じ。
// +ボタン用コマンド public OperatorCommand Plus = new OperatorCommand(new Operator(1, "+", false) { @Override public double calculate(double operandA, double operandB) { return operandA + operandB; } }); // ーボタン用コマンド public OperatorCommand Minus = new OperatorCommand(new Operator(1, "-", false) { @Override public double calculate(double operandA, double operandB) { return operandA - operandB; } }); // ×ボタン用コマンド public OperatorCommand Multiply = new OperatorCommand(new Operator(2, "x", false) { @Override public double calculate(double operandA, double operandB) { return operandA * operandB; } }); // ÷ボタン用コマンド public OperatorCommand Divide = new OperatorCommand(new Operator(2, "/", false) { @Override public double calculate(double operandA, double operandB) { return operandA / operandB; } }); // =ボタン用コマンド public OperatorCommand Equal = new OperatorCommand(new Operator(0, "=", true) { @Override public double calculate(double operandA, double operandB) { return operandA; } }); // 演算ボタンアクションに対応するコマンドクラス private class OperatorCommand extends Command { private final Operator _operator; public OperatorCommand(Operator operator) { _operator = operator; } @Override public void Invoke(View arg0, Object... arg1) { operate(_operator); } }
NumberCommandクラスと同様に、OperatorCommandクラスもCommand抽象クラスを拡張して定義しています。コンストラクタの引数でバリエーションを増やすやり方は常套手段のようですね。
いつものようにこちらにコードを上げておきます。ご参考下さいませ。
というわけで、2つのAndroid Bindingの事例を見て来ました。とても簡単な事例ですが、それでもとても興味深い内容でした。これ、日常的に使えるようになりたいなぁ。また週末やろ。