レイアウトとバインディング式

式言語を使用すると、ディスパッチされたイベントを処理する式を記述できます。 視聴回数で表します。データ バインディング ライブラリは、必要なクラスを を使用して、レイアウト内のビューをデータ オブジェクトをバインドします。

データ バインディングのレイアウト ファイルは若干異なり、次のルートタグで始まります。 layout の後に data 要素と view ルート要素が続きます。このビュー 要素は、バインディングのないレイアウト ファイル内のルート要素です。次のコードでは、 に、サンプルのレイアウト ファイルを示します。

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
   <data>
       <variable name="user" type="com.example.User"/>
   </data>
   <LinearLayout
       android:orientation="vertical"
       android:layout_width="match_parent"
       android:layout_height="match_parent">
       <TextView android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:text="@{user.firstName}"/>
       <TextView android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:text="@{user.lastName}"/>
   </LinearLayout>
</layout>

data 内の user 変数は、内部で使用できるプロパティを表します。 このレイアウトは

<variable name="user" type="com.example.User" />

レイアウト内の式は、 @{} 構文。次の例では、 TextView テキストは user 変数の firstName プロパティ:

<TextView android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:text="@{user.firstName}" />

データ オブジェクト

User エンティティを記述するプレーン オブジェクトがあるとします。

Kotlin

data class User(val firstName: String, val lastName: String)

Java

public class User {
  public final String firstName;
  public final String lastName;
  public User(String firstName, String lastName) {
      this.firstName = firstName;
      this.lastName = lastName;
  }
}

この型のオブジェクトには、変更されることがないデータが格納されます。一般的に、アプリでは 一度読み取られ、その後変更されないデータですまた、kubectl の たとえば、 Java プログラミング言語で利用できます。

Kotlin

// Not applicable in Kotlin.
data class User(val firstName: String, val lastName: String)

Java

public class User {
  private final String firstName;
  private final String lastName;
  public User(String firstName, String lastName) {
      this.firstName = firstName;
      this.lastName = lastName;
  }
  public String getFirstName() {
      return this.firstName;
  }
  public String getLastName() {
      return this.lastName;
  }
}

データ バインディングの観点からすると、これら 2 つのクラスは同等です。「 次に使用される式 @{user.firstName} android:text 属性は、前のクラスの firstName フィールドにアクセスし、 後者のクラスのgetFirstName()メソッドを使用します。また、 firstName()(メソッドが存在する場合)。

データのバインド

バインディング クラスはレイアウト ファイルごとに生成されます。デフォルトでは、 クラスは、パスカルケースに変換されたレイアウト ファイルの名前に基づいており、 Binding サフィックスが追加されます。たとえば、上のレイアウト ファイル名は、 activity_main.xml。対応する生成されるバインディング クラス: ActivityMainBinding。

このクラスは、レイアウト プロパティのすべてのバインディングを保持します。たとえば、 user 変数(レイアウトのビューに割り当て、値の割り当て方法がわかっているもの) バインディング式を指定しますインフレート中にバインディングを作成することをおすすめします。 配置する必要があります。

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    val binding: ActivityMainBinding = DataBindingUtil.setContentView(
            this, R.layout.activity_main)

    binding.user = User("Test", "User")
}

Java

@Override
protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
   User user = new User("Test", "User");
   binding.setUser(user);
}

実行時に、アプリの UI に Test ユーザーが表示されます。別の方法として、 使用してビューを取得 LayoutInflater: 次の例をご覧ください。

Kotlin

val binding: ActivityMainBinding = ActivityMainBinding.inflate(getLayoutInflater())

Java

ActivityMainBinding binding = ActivityMainBinding.inflate(getLayoutInflater());

データ バインディング アイテムを Fragment ListView、または RecyclerView 使用する場合は、 inflate() バインディング クラスのメソッド、または DataBindingUtil クラスを 次のコードサンプルをご覧ください。

Kotlin

val listItemBinding = ListItemBinding.inflate(layoutInflater, viewGroup, false)
// or
val listItemBinding = DataBindingUtil.inflate(layoutInflater, R.layout.list_item, viewGroup, false)

Java

ListItemBinding binding = ListItemBinding.inflate(layoutInflater, viewGroup, false);
// or
ListItemBinding binding = DataBindingUtil.inflate(layoutInflater, R.layout.list_item, viewGroup, false);

式言語

一般的な機能

式言語はマネージコードの式によく似ています。マイページ 式言語で次の演算子とキーワードを使用できます。

  • 数学: + - / * %
  • 文字列の連結: +
  • 論理: && ||
  • バイナリ: & | ^
  • 単項: + - ! ~
  • シフト: >> >>> <<
  • 比較: == > < >= <=(< は &lt; としてエスケープする必要があります)
  • instanceof
  • グループ: ()
  • リテラル(文字、文字列、数値、null など)
  • キャスト
  • メソッド呼び出し
  • フィールド アクセス
  • 配列アクセス: []
  • 3 項演算子: ?:

次に例を示します。

android:text="@{String.valueOf(index + 1)}"
android:visibility="@{age > 13 ? View.GONE : View.VISIBLE}"
android:transitionName='@{"image_" + id}'

使用できない演算

使用可能な式の構文に、次の演算がありません マネージド・コードで:

  • this
  • super
  • new
  • 明示的な汎用呼び出し

null 合体演算子

null 合体演算子(??)が null でない場合、左のオペランドを選択します 前者が null の場合は右になります。

android:text="@{user.displayName ?? user.lastName}"

これは機能的に以下と同等です。

android:text="@{user.displayName != null ? user.displayName : user.lastName}"

プロパティ参照

式は、次の形式を使用してクラス内のプロパティを参照できます。 これはフィールド、ゲッター、 ObservableField オブジェクト:

android:text="@{user.lastName}"

null ポインタ例外を回避する

生成されたデータ バインディング コードは null 値を自動的にチェックし、 null ポインタ例外。たとえば、式 @{user.name} で、 user が null の場合、user.name にはデフォルト値の null が割り当てられます。もし 参照 user.age(age が int 型)の場合、データ バインディングでは デフォルト値は 0 です。

ビューの参照

式は、以下を使用して ID でレイアウト内の他のビューを参照できます。 構文:

android:text="@{exampleText.text}"

次の例では、TextView ビューが次の EditText ビューを参照しています。 行います。

<EditText
    android:id="@+id/example_text"
    android:layout_height="wrap_content"
    android:layout_width="match_parent"/>
<TextView
    android:id="@+id/example_output"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@{exampleText.text}"/>

コレクション

一般的なコレクション(配列、リスト、スパース リスト、 便宜上 [] 演算子を使用します。

<data>
    <import type="android.util.SparseArray"/>
    <import type="java.util.Map"/>
    <import type="java.util.List"/>
    <variable name="list" type="List&lt;String>"/>
    <variable name="sparse" type="SparseArray&lt;String>"/>
    <variable name="map" type="Map&lt;String, String>"/>
    <variable name="index" type="int"/>
    <variable name="key" type="String"/>
</data>
...
android:text="@{list[index]}"
...
android:text="@{sparse[index]}"
...
android:text="@{map[key]}"

object.key 表記を使用して、マップの値を参照することもできます。対象 たとえば、上記の例の @{map[key]} を @{map.key}。

文字列リテラル

属性値を単一引用符で囲むと、 二重引用符で囲む必要があります。

android:text='@{map["firstName"]}'

二重引用符で属性値を囲むこともできます。その際、 次に示すように、文字列リテラルはバッククォート ` で囲む必要があります。 こちらをご覧ください。

android:text="@{map[`firstName`]}"

リソース

次の構文により、式でアプリのリソースを参照できます。

android:padding="@{large? @dimen/largePadding : @dimen/smallPadding}"

パラメータを指定することにより、書式設定文字列と複数形を評価できます。

android:text="@{@string/nameFormat(firstName, lastName)}"
android:text="@{@plurals/banana(bananaCount)}"

プロパティ参照とビュー リソース パラメータとして渡す参照:

android:text="@{@string/example_resource(user.lastName, exampleText.text)}"

複数形が複数のパラメータを取る場合は、すべてのパラメータを渡します。


  Have an orange
  Have %d oranges

android:text="@{@plurals/orange(orangeCount, orangeCount)}"

一部のリソースでは、次に示すように、明示的な型の評価が必要です。 table:

タイプ 通常の参照 式参照
String[] @array @stringArray
int[] @array @intArray
TypedArray @array @typedArray
Animator @animator @animator
StateListAnimator @animator @stateListAnimator
color int @color @color
ColorStateList @color @colorStateList

イベント処理

データ バインディングを使用すると、イベントを処理する式を記述して、 ビュー(たとえば、 onClick() メソッドを呼び出します。イベント属性名は、リスナー メソッドの名前によって決定されます。 いくつか例外がありますたとえば View.OnClickListener の例: メソッド onClick() なので、このイベントの属性は android:onClick です。

クリック イベント専用のイベント ハンドラがいくつかあり、 android:onClick 以外の属性を指定することをおすすめします。こちらの 次の属性を追加して、この種の競合を回避してください。

クラス リスナーのセッター 属性
SearchView setOnSearchClickListener(View.OnClickListener) android:onSearchClick
ZoomControls setOnZoomInClickListener(View.OnClickListener) android:onZoomIn
ZoomControls setOnZoomOutClickListener(View.OnClickListener) android:onZoomOut

この 2 つのメカニズムを使用できます。詳細については、 イベントを処理します。

  • メソッド参照: 式では、 リスナー メソッドのシグネチャに適合する参照メソッドが含まれます。日時 式はメソッド参照として評価され、データ バインディングによってメソッドがラップされる オーナー オブジェクトを参照し、そのリスナーを ターゲット ビューです。式が null と評価された場合、データ バインディングは実行されません。 代わりにリスナーを作成し、null リスナーを設定してください。
  • リスナー バインディング: リスナー バインディング イベント発生時に評価されますデータ バインディングでは常に、 ビューに設定します。イベントがディスパッチされると、 リスナーはラムダ式を評価します。

メソッド参照

他の処理と同様に、イベントをハンドラ メソッドに直接バインドできます。 割り当て android:onClick を メソッドを呼び出せますGoogle Workspace の View onClick 属性は、 コンパイル時に処理されます。そのため、このメソッドが存在しない場合や、 コンパイル時エラーが発生します。

メソッド参照とリスナー バインディングの主な違いは、 実際のリスナーの実装は、データがバインドされた時点で作成され、 イベントがトリガーされます。イベントが発生したときに式を評価したい場合は、 リスナー バインディングを使用してください。

イベントをそのハンドラに割り当てるには、通常のバインディング式を使用して、 value は呼び出すメソッド名です。たとえば、次の例をご覧ください。 レイアウト データ オブジェクト:

Kotlin

class MyHandlers {
    fun onClickFriend(view: View) { ... }
}

Java

public class MyHandlers {
    public void onClickFriend(View view) { ... }
}

バインディング式では、ビューのクリック リスナーを onClickFriend() メソッドを次のように指定します。

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
   <data>
       <variable name="handlers" type="com.example.MyHandlers"/>
       <variable name="user" type="com.example.User"/>
   </data>
   <LinearLayout
       android:orientation="vertical"
       android:layout_width="match_parent"
       android:layout_height="match_parent">
       <TextView android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:text="@{user.firstName}"
           android:onClick="@{handlers::onClickFriend}"/>
   </LinearLayout>
</layout>

リスナー バインディング

リスナー バインディングは、イベントの発生時に実行されるバインディング式です。。 メソッド参照に似ていますが、任意のデータ バインディングを実行できる 表します。この機能は Gradle 用 Android Gradle プラグインで使用できます 使用できます。

メソッド参照では、メソッドのパラメータは、 イベントリスナー。リスナー バインディングでは、戻り値のみが リスナーの期待される戻り値(void が想定されている場合を除く)。対象 たとえば、onSaveClick() がある次のプレゼンター クラスについて考えてみましょう。 メソッド:

Kotlin

class Presenter {
    fun onSaveClick(task: Task){}
}

Java

public class Presenter {
    public void onSaveClick(Task task){}
}

次のように、クリック イベントを onSaveClick() メソッドにバインドできます。

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <variable name="task" type="com.android.example.Task" />
        <variable name="presenter" type="com.android.example.Presenter" />
    </data>
    <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent">
        <Button android:layout_width="wrap_content" android:layout_height="wrap_content"
        android:onClick="@{() -> presenter.onSaveClick(task)}" />
    </LinearLayout>
</layout>

式でコールバックを使用すると、データ バインディングによって自動的に それをイベントに登録します。ビューが イベントが発生すると、データ バインディングは指定された式を評価します。通常のバインディングと同じ null とスレッドの安全性を確保しながら、データ バインディングを 評価しています。

上記の例では、onClick(View) に渡される view パラメータ 定義します。リスナー バインディングでは、リスナー パラメータに次の 2 つの選択肢があります。 メソッドのすべてのパラメータを無視することも、すべてのパラメータに名前を付けることもできます。ご希望の場合 パラメータに名前を付ける場合は、式で使用できます。たとえば、 上の式は次のように記述できます。

android:onClick="@{(view) -> presenter.onSaveClick(task)}"

パラメータを式で使用する場合は、次の操作を行います。

Kotlin

class Presenter {
    fun onSaveClick(view: View, task: Task){}
}

Java

public class Presenter {
    public void onSaveClick(View view, Task task){}
}
android:onClick="@{(theView) -> presenter.onSaveClick(theView, task)}"

また、ラムダ式と複数のパラメータを使用できます。

Kotlin

class Presenter {
    fun onCompletedChanged(task: Task, completed: Boolean){}
}

Java

public class Presenter {
    public void onCompletedChanged(Task task, boolean completed){}
}
<CheckBox android:layout_width="wrap_content" android:layout_height="wrap_content"
      android:onCheckedChanged="@{(cb, isChecked) -> presenter.completeChanged(task, isChecked)}" />

リッスンしているイベントが void 以外の型の値を返す場合、 式も同じ型の値を返す必要があります。たとえば 感知して長押し(長押し)イベントがある場合、式は ブール値を返します。

Kotlin

class Presenter {
    fun onLongClick(view: View, task: Task): Boolean { }
}

Java

public class Presenter {
    public boolean onLongClick(View view, Task task) { }
}
android:onLongClick="@{(theView) -> presenter.onLongClick(theView, task)}"

null オブジェクトが原因で式を評価できない場合、データ バインディングは その型のデフォルト値(参照型の null、0 など)。 int、または boolean の場合は false。

述語を含む式を使用する必要がある場合(例: - 記号として void を使用できます。

android:onClick="@{(v) -> v.isVisible() ? doSomething() : void}"

複雑なリスナーを使用しない

リスナー式は強力で、コードを読みやすくします。 一方、リスナーに複雑な式が含まれていると、レイアウトが難しくなります 管理する必要がありません。利用可能なデータを渡して式をシンプルに保つ コールバックメソッドに渡します内部にビジネス ロジックを実装する。 コールバック関数を呼び出します。

インポート、変数、インクルード

データ バインディング ライブラリには、インポート、変数、 含まれます。インポートにより、レイアウト ファイル内でクラスを参照しやすくなります。 変数を使用すると、バインディング式で使用できるプロパティを記述できます。 インクルードを使用すると、複雑なレイアウトをアプリ全体で再利用できます。

インポート

インポートを使用すると、マネージド コードと同様に、レイアウト ファイル内でクラスを参照できます。 data 要素内では、0 個以上の import 要素を使用できます。「 次のコード例では、View クラスをレイアウト ファイルにインポートしています。

<data>
    <import type="android.view.View"/>
</data>

View クラスをインポートすると、バインディング式から参照できます。 次の例は、Terraform で参照する Pod の VISIBLE、 View クラスの GONE 定数:

<TextView
   android:text="@{user.lastName}"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:visibility="@{user.isAdult ? View.VISIBLE : View.GONE}"/>

型のエイリアス

クラス名が競合する場合は、いずれかのクラスの名前を 使用します。次の例では、View クラスの名前を com.example.real.estate パッケージを Vista に追加します。

<import type="android.view.View"/>
<import type="com.example.real.estate.View"
        alias="Vista"/>

その後、Vista を使用して com.example.real.estate.View と View を参照できます。 レイアウト ファイル内で android.view.View を参照しています。

他のクラスをインポートする

インポートした型は、変数と式での型参照として使用できます。「 次の例では、変数の型として User と List が使用されています。

<data>
    <import type="com.example.User"/>
    <import type="java.util.List"/>
    <variable name="user" type="User"/>
    <variable name="userList" type="List&lt;User>"/>
</data>

インポートされた型を使用して、式の一部をキャストできます。次の この例では、connection プロパティを User の型にキャストしています。

<TextView
   android:text="@{((User)(user.connection)).lastName}"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"/>

また、インポートされた型は、 表します。次のコードは、MyStringUtils クラスをインポートして参照します。 capitalize メソッドを使用します。

<data>
    <import type="com.example.MyStringUtils"/>
    <variable name="user" type="com.example.User"/>
</data>
…
<TextView
   android:text="@{MyStringUtils.capitalize(user.lastName)}"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"/>

マネージコードと同様に、java.lang.* は自動的にインポートされます。

変数

data 要素内で複数の variable 要素を使用できます。各 variable 要素は、使用するレイアウトに設定できるプロパティを記述します。 レイアウト ファイル内のバインディング式で使用できます。次の例では、 user、image、note 変数:

<data>
    <import type="android.graphics.drawable.Drawable"/>
    <variable name="user" type="com.example.User"/>
    <variable name="image" type="Drawable"/>
    <variable name="note" type="String"/>
</data>

変数の型はコンパイル時に検査されるため、変数に Observable または 監視可能なコレクション 型に反映する必要があります。変数が基本クラスまたはインターフェースの場合 Observable インターフェースを実装していないアプリの場合、変数は 表示されます。

さまざまな構成(たとえば、 横向き、縦向きなど)に応じて、変数が組み合わされます。重複しない 変数定義が競合する場合があるからです。

生成されるバインディング クラスには、記述された各要素のセッターとゲッターが 使用します。セッターまで、変数はマネージド コードのデフォルト値を取ります。 が呼び出されます。null は参照タイプ、0 は int、false は boolean など

バインディング式で使用するために context という名前の特殊な変数が生成されます。 できます。context の値は、 Context オブジェクト(ルートビューの getContext() メソッドを使用します。「 context 変数は、明示的な変数宣言によってオーバーライドされます。 表示されます。

インクルード

含まれるレイアウトのバインディングに、変数を渡すことができます。 属性でアプリの名前空間と変数名を使用して作成します。「 次の例では、name.xml からインクルードされた user 変数と、 contact.xml レイアウト ファイル:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:bind="http://schemas.android.com/apk/res-auto">
   <data>
       <variable name="user" type="com.example.User"/>
   </data>
   <LinearLayout
       android:orientation="vertical"
       android:layout_width="match_parent"
       android:layout_height="match_parent">
       <include layout="@layout/name"
           bind:user="@{user}"/>
       <include layout="@layout/contact"
           bind:user="@{user}"/>
   </LinearLayout>
</layout>

データ バインディングでは、merge 要素の直接の子としての include はサポートされていません。 たとえば、次のレイアウトはサポートされていません。

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:bind="http://schemas.android.com/apk/res-auto">
   <data>
       <variable name="user" type="com.example.User"/>
   </data>
   <merge><!-- Doesn't work -->
       <include layout="@layout/name"
           bind:user="@{user}"/>
       <include layout="@layout/contact"
           bind:user="@{user}"/>
   </merge>
</layout>

参考情報

データ バインディングについて詳しくは、以下の参考リンクをご覧ください。

サンプル

Codelab

ブログ投稿