こんにちは。
最近使い始めて便利だと思ったツールはのDropBox Paper、mukaiyachiです。
先日以前より気になっていたData Bindingを入門程度ですが使ってみました。
DataBindingとは?
Google I/O 2015(2015年5月)にAndroid M Developer Previewと共に発表された技術。
レイアウトのViewの要素とJavaオブジェクトのデータをBindしてくれる機能。
通常はプログラム上でfindViewById()を使って各Viewとデータを結びつけ、さらに、例えばTextViewであればsetText()でデータをセットするといった作業が必要ですが、Data BindingはXML内で宣言的に書けるようになります。
要はJavaオブジェクトの状態に応じて、レイアウトのViewの内容を変更ができるということです。
Data BindingはAndroid 2.1(APIレベル7)以降で使用できます。
メリット
- コードを簡略化できる。ActivityやFragment の肥大化を防げる。
- Viewの操作をXmlで完結できる。
- Viewとロジックの分離が楽になる。
- レイアウトを使い回す場合、複数箇所で同じようなセットするコードを書かなくて良い。など
デメリット
- 学習コストが高い。
- チームで認識の共有が必要。
- 既存のプロジェクトで採用した場合、大幅な変更が必要。
- 高度な機能を使う場合はアプリの基本設計をきちんと考える必要がある。
- 新しい技術で実績がほとんどない。
など
使い方
1、[app]フォルダ内のbuild.gradleに以下を記述
1 2 3 |
dataBinding { enabled = true } |
2、レイアウトとBindするデータクラスを作成
いくつかフィールド変数があって、Getter、Setterがあるようなデータを格納するクラスを用意します。今回は例としてUserクラスを作成しました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
public class User { private String firstName; private String lastName; public User(String firstName, String lastName) { this.firstName = firstName; this.lastName = lastName; } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } } |
3、レイアウトの作成
■Data Bindingを使用する場合、ルートの要素は<layout>タグ
通常ならルートの要素は<LinearLayout>タグや<RelativeLayout>タグですが、DataBindingを使用する場合、ルートの要素は<layout>タグになります。
1 2 3 4 5 6 |
<<??xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" tools:context="jp.co.itcowork.databindingdemo.MainActivity"> </layout> |
■<data>タグ&<variable>タグのバインド対象のメンバーとクラスを指定
- ルート要素のlayoutタグの中に、dataタグを記述し、さらにimportや宣言を書く。
- variableタグで使うクラスと変数名を宣言。
- variableの宣言によって各View内の値としてJavaオブジェクトが使用できる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<<??xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" tools:context="jp.co.itcowork.databindingdemo.MainActivity"> <data> <!-- Userクラスにバインドする --> <variable name="user" type="jp.co.itcowork.databindingdemo.User"/> <!-- importを使った書き方もできる --> <!-- <import type="jp.co.itcowork.databindingdemo.User"/> <variable name="user" type="User"/> --> </data> |
■Viewの必要な箇所で@{}の中にデータ取得処理を記述
例えばUserオブジェクトを使用するには、android:text=”@{user.lastName}”のように@{}で挟みます。
1 2 3 4 5 6 |
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="8dp" android:text="@{user.lastName}" android:textAppearance="@style/Base.TextAppearance.AppCompat.Medium"/> |
4、ActivityでBind
■レイアウトファイルに対応してBinding用のクラスが自動生成される
自動生成されるクラス名はlayoutのファイル名に依存しています。
例えばBindするレイアウトがactivity_main.xmlの場合はActivityMainBindingクラスが、view_item.xmlというファイルの場合はViewItemBindingクラスが生成されます。
■インスタンス化
その自動生成されたクラスをインスタンス化します。
1 2 3 4 5 6 7 8 9 |
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Bindingオブジェクトを取得 ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main); } } |
5、Bindingオブジェクトにデータをセット
1 2 3 4 5 6 7 8 9 10 11 12 |
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Bindingオブジェクトを取得 ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main); // BindingオブジェクトにUserをセット binding.setUser(new User("taro", "hachinohe")); } } |
binding.setUser(bindするデータ)で、findViewByIdしてsetTextとしなくてもTextViewに値が反映されます。
■set◯◯メソッド
データをセットする際にsetUser()を使用していますが、このset◯◯というメソッド名は、レイアウトの<variable>タグのname属性に依存しています。
1 2 3 |
<variable name="user" type="jp.co.itcowork.databindingdemo.User"/> |
■Viewにidが指定してあるとBindingオブジェクトからViewへの参照が取得可能
例えばTextViewのid名をtimeTextViewとすることで、Java側でbinding.timeTextViewでアクセスすることができます。
1 2 3 4 5 |
<TextView android:id="@+id/timeTextView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="8dp" /> |
1 2 3 4 |
// 時間を扱うフィールドはUserにないけど、Viewにidが指定してあると、 // BindingオブジェクトからViewへの参照が取得可能なので、参照して値をセットできる String date = String.valueOf(DateFormat.format("yyyy年MM月dd日(E) HH時mm分", Calendar.getInstance())); binding.timeTextView.setText(date); |
■可変なデータオブジェクトをbindして自動的に更新
これには主に2通りの方法があります。
1. BaseObservableクラスを継承してObservableオブジェクトを定義
- Getterもしくはfieldどちらかに @Bindable アノテーションを付ける。
- @Bindable アノテーションを付けると BR クラスが自動で作成される。
- Setterで notifyPropertyChanged メソッドを呼び出すことで、どのフィールドが変化したかの通知が行われる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
public class User extends BaseObservable { // 普通のフィールド // Getter・Setter必要 private String firstName; private String lastName; public User(String firstName, String lastName) { this.firstName = firstName; this.lastName = lastName; } // Observableオブジェクト(Observableクラスの継承必要あり) // Bindableアノテーションを指定することでSetterに通知する // BindableアノテーションはGetterもしくはfieldにつける // SetterではBR.firstNameという定数で参照する // Setしたら自動でGetする @Bindable public String getFirstName() { return firstName; } public String getLastName() { return lastName; } public void setFirstName(String firstName) { this.firstName = firstName; // 更新メソッド(Observableクラスの継承必要あり) notifyPropertyChanged(jp.co.itcowork.databindingdemo.BR.firstName); } public void setLastName(String lastName) { this.lastName = lastName; } /** * クリックイベント * 例としてボタンを押したら姓と名の表示変更を行う処理 * @param view */ public void changeName(View view) { setFirstName("太郎"); // Observableオブジェクトなので表示が自動的に変更される setLastName("八戸"); // Observableオブジェクトではないので表示は自動的に変更されない } } |
changeName()は、画面上に変更ボタンがあって、そのボタンが押された際に、姓名の表示変更を行うメソッドだと思ってください。
firsetNameはObservableオブジェクトなので、ボタンが押されて値が変更された後、すぐに画面の表示に反映されますが、lastNameはObservableオブジェクトではないので表示は変わりません。
2. Observableフィールドを使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
public class User { // Observableフィールド(BaseObservableクラスの継承必要なし) // Getter・Setter不要 databindingをONにしたら使用可能 public ObservableField<String> firstName = new ObservableField<>(); public ObservableField<String> lastName = new ObservableField<>(); public ObservableInt age = new ObservableInt(); public ObservableInt likes = new ObservableInt(); public User(String firstName, String lastName, int age) { this.firstName.set(firstName); this.lastName.set(lastName); this.age.set(age); this.likes.set(0); } /** * クリックイベント * 例としてボタンを押したら姓と名の表示変更を行う処理 * @param view */ public void changeName(View view) { firstName.set("太郎"); // Observableフィールドなので表示が自動的に変更される lastName.set("八戸"); // Observableフィールドなので表示が自動的に変更される } public void pushLike(View view) { likes.set(likes.get() + 1); } } |
ObservableフィールドはData BindingをONにしたら使用可能になるもので、フィールドを用意すればGetter、Setterは不要です。
set()やget()といったメソッドが使用できるので、それらを使用して操作します。
changeName()が呼ばれるとfirstName、lastNameどちらもObservableフィールドなので、ボタンが押されて値が変更された後、すぐに画面の表示に反映されます。
以上になりますが、Data Bindingは他にもクリックイベントをBindしたり、レイアウトの中で条件分岐を行えたりなど様々なことを行うことが可能です。
興味がある方は公式ドキュメントをご覧になってみてください。
便利そうなのでまずは趣味で個人アプリを作る際に使ってみようかと思います。
以上となります。
みなさんも気になりましたらぜひお試しください。