監視可能とは、オブジェクトがそのデータの変更について他のオブジェクトに通知できることを意味します。データ バインディング ライブラリを使用すると、オブジェクト、フィールド、コレクションを監視できるようになります。
従来のオブジェクトはデータ バインディングに使用できますが、オブジェクトを変更しても UI は自動的に更新されません。データ バインディングを使用すると、データ オブジェクトのデータが変更されたときに他のオブジェクト(リスナー)に通知することができます。監視可能なクラスには、オブジェクト、フィールド、コレクションの 3 種類があります。
これらの監視可能なデータ オブジェクトのいずれかが UI にバインドされている場合、データ オブジェクトのプロパティが変更されると、UI が自動的に更新されます。
監視可能なフィールド
Observable
インターフェースを実装するクラスの作成には一定の労力がかかります。ただし、クラスにプロパティが数個しかない場合は、その労力に見合わないかもしれません。そのような場合、汎用の Observable
クラスや以下のプリミティブ固有のクラスを使用して、フィールドの監視を行えるようにできます。
ObservableBoolean
ObservableByte
ObservableChar
ObservableShort
ObservableInt
ObservableLong
ObservableFloat
ObservableDouble
ObservableParcelable
監視可能なフィールドとは、1 つのフィールドを持つ自己完結型の監視可能なオブジェクトです。プリミティブ バージョンを使用すると、アクセス操作中にボックス化とボックス化解除が行われないようにすることができます。このメカニズムを使用するには、次の例に示すように、Java プログラミング言語で public final
プロパティを作成するか、Kotlin で読み取り専用のプロパティを作成します。
Kotlin
class User { val firstName = ObservableField<String>() val lastName = ObservableField<String>() val age = ObservableInt() }
Java
private static class User { public final ObservableField<String> firstName = new ObservableField<>(); public final ObservableField<String> lastName = new ObservableField<>(); public final ObservableInt age = new ObservableInt(); }
フィールドの値にアクセスするには、アクセサ メソッド set()
と get()
を使用するか、Kotlin プロパティ構文を使用します。
Kotlin
user.firstName = "Google" val age = user.age
Java
user.firstName.set("Google"); int age = user.age.get();
監視可能なコレクション
アプリによっては、データを保持するために動的な構造を使用することがあります。監視可能なコレクションを使用すると、こうした構造にキーを使ってアクセスできます。次の例に示すように、キーが参照型(String
など)の場合は、ObservableArrayMap
クラスが便利です。
Kotlin
ObservableArrayMap<String, Any>().apply { put("firstName", "Google") put("lastName", "Inc.") put("age", 17) }
Java
ObservableArrayMap<String, Object> user = new ObservableArrayMap<>(); user.put("firstName", "Google"); user.put("lastName", "Inc."); user.put("age", 17);
レイアウトでは、次のように文字列キーを使用してマップを検出できます。
<data>
<import type="android.databinding.ObservableMap"/>
<variable name="user" type="ObservableMap<String, Object>"/>
</data>
…
<TextView
android:text="@{user.lastName}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:text="@{String.valueOf(1 + (Integer)user.age)}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
次のように、キーが整数の場合は、ObservableArrayList
クラスが便利です。
Kotlin
ObservableArrayList<Any>().apply { add("Google") add("Inc.") add(17) }
Java
ObservableArrayList<Object> user = new ObservableArrayList<>(); user.add("Google"); user.add("Inc."); user.add(17);
レイアウトでは、次の例に示すように、インデックスを介してリストにアクセスできます。
<data>
<import type="android.databinding.ObservableList"/>
<import type="com.example.my.app.Fields"/>
<variable name="user" type="ObservableList<Object>"/>
</data>
…
<TextView
android:text='@{user[Fields.LAST_NAME]}'
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:text='@{String.valueOf(1 + (Integer)user[Fields.AGE])}'
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
監視可能なオブジェクト
Observable
インターフェースを実装するクラスを使用すると、監視可能なオブジェクトでプロパティの変更に関する通知を受け取るリスナーを登録できます。
Observable
インターフェースにはリスナーの追加と削除を行うメカニズムがありますが、通知の送信タイミングはデベロッパーが決める必要があります。データ バインディング ライブラリにはリスナーの登録メカニズムを実装する BaseObservable
クラスが用意されており、このクラスを利用することで開発を簡素化できます。BaseObservable
を実装するデータクラスは、プロパティの変更時に通知を送信します。そのためには、次の例に示すように、Bindable
アノテーションをゲッターに付与し、セッターで notifyPropertyChanged()
メソッドを呼び出します。
Kotlin
class User : BaseObservable() { @get:Bindable var firstName: String = "" set(value) { field = value notifyPropertyChanged(BR.firstName) } @get:Bindable var lastName: String = "" set(value) { field = value notifyPropertyChanged(BR.lastName) } }
Java
private static class User extends BaseObservable { private String firstName; private String lastName; @Bindable public String getFirstName() { return this.firstName; } @Bindable public String getLastName() { return this.lastName; } public void setFirstName(String firstName) { this.firstName = firstName; notifyPropertyChanged(BR.firstName); } public void setLastName(String lastName) { this.lastName = lastName; notifyPropertyChanged(BR.lastName); } }
データ バインディングでは、BR
という名前のクラスがモジュール パッケージ内に生成されます。このクラスに、データ バインディングで使用するリソースの ID が格納されます。Bindable
アノテーションを付与すると、コンパイル時に BR
クラスのファイル内にエントリが生成されます。データクラスの基本クラスを変更できない場合でも、PropertyChangeRegistry
オブジェクトを使用して Observable
インターフェースを実装することで、リスナーの登録と通知を効率的に行うことができます。
参考情報
データ バインディングの詳細については、以下の参考情報をご確認ください。