Data Binding 数据绑定

Data Binding 数据绑定

温馨提示:本文最后更新于2025-11-24 09:28:10,某些文章具有时效性,若有错误或已失效,请在下方留言

Data Binding(数据绑定) 是一个支持库,它允许你在布局中使用声明式格式将 UI 组件绑定到应用中的数据源,而不是通过代码进行绑定。

数据绑定是将 XML 布局中的视图与数据对象进行整合的过程。Data Binding 负责生成此过程中所需的类。使用数据绑定时,系统会创建一个 binding 对象,其中包含对布局中每个视图的引用,因此 Android 系统不需要再通过视图 ID 一次次地去查找这些视图。

数据绑定基本使用

布局文件被 <layout></layout> 包裹,其名称是 activity_main。基于此,Android Data Binding 库将会创建一个名为 ActvityMainBinding 的绑定对象。

1. 开启数据绑定

build.gradle.kts (Module:app) 文件中,添加如下的代码开启 Data Binding

plugins {
    alias(libs.plugins.android.application)
}

android {
    namespace = "com.stewednoodles.databindingapp"
    compileSdk {
        version = release(36)
    }

    defaultConfig {
        applicationId = "com.stewednoodles.databindingapp"
        minSdk = 24
        targetSdk = 36
        versionCode = 1
        versionName = "1.0"

        testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            isMinifyEnabled = false
            proguardFiles(
                getDefaultProguardFile("proguard-android-optimize.txt"),
                "proguard-rules.pro"
            )
        }
    }
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_11
        targetCompatibility = JavaVersion.VERSION_11
    }

    // 1. 开启 data binding
    buildFeatures {
        dataBinding = true
    }
}

dependencies {
    implementation(libs.appcompat)
    implementation(libs.material)
    implementation(libs.activity)
    implementation(libs.constraintlayout)
    testImplementation(libs.junit)
    androidTestImplementation(libs.ext.junit)
    androidTestImplementation(libs.espresso.core)
}

2. <layout> 标记

<layout></layout> 作为根元素,对布局文件进行标记。

<?xml version="1.0" encoding="utf-8"?>
<!--2. <layout> 作为根元素进行标记-->
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">
    <!--3. 数据绑定
         - person 变量绑定 Person 类
         - person 变量的使用方式 @{person.name}
     -->
    <data>
        <variable
            name="person"
            type="com.stewednoodles.databindingapp.Person" />
    </data>
    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/main"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{person.name}"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

3. 数据的绑定

使用<data><variable> 标签进行数据的绑定,下面的代码就是将变量 person 绑定到 Person 实例中。

<!--3. 数据绑定
     - person 变量绑定 Person 类
     - person 变量的使用方式 @{person.name}
 -->
<data>
    <variable
        name="person"
        type="com.stewednoodles.databindingapp.Person" />
</data>

Person 文件的内容

package com.stewednoodles.databindingapp;

public class Person {
    private String name;
    private String email;

    public Person(String name, String email) {
        this.name = name;
        this.email = email;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public Person() {
    }
}

4. 变量的使用

变量绑定之后,使用 @{} 对变量进行引用。

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@{person.name}"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent" />

5. MainActivity

MainActivity 中的代码,如下所示

package com.stewednoodles.databindingapp;

import android.os.Bundle;

import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import androidx.databinding.DataBindingUtil;

import com.stewednoodles.databindingapp.databinding.ActivityMainBinding;

public class MainActivity extends AppCompatActivity {

    //
    private ActivityMainBinding binding;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        EdgeToEdge.enable(this);
        setContentView(R.layout.activity_main);
        ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
            Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
            v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
            return insets;
        });
        // 数据实例
        Person person = new Person("Stewed Noodles", "stewednoodles.co@gmail.com");

        // 绑定数据
        binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
        binding.setPerson(person);
    }
}

6. 运行效果

最终的运行效果,如下图所示

图片[1]-Data Binding 数据绑定-Stewed Noodles 资源
运行效果

数据绑定事件处理

1. 创建事件处理类

添加事件处理类 MyClickHandler,代码内容如下所示

package com.stewednoodles.databindingapp;

import android.content.Context;
import android.view.View;
import android.widget.Toast;

public class MyClickHandler {
    Context mContext;

    public MyClickHandler(Context mContext) {
        this.mContext = mContext;
    }

    public void onButton1Click(View view) {
        Toast.makeText(mContext, "First Button is clicked!", Toast.LENGTH_SHORT).show();
    }
}

2. 创建<data> 标签变量

在布局文件 activity_main.xml 文件的 <data> 标签中,引入 clickHandler 变量。

<?xml version="1.0" encoding="utf-8"?><!--2. <layout> 作为根元素进行标记-->
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">
    <!--3. 数据绑定
         - person 变量绑定 Person 类
         - person 变量的使用方式 @{person.name}
     -->
    <data>
        <!--创建变量-->
        <variable
            name="person"
            type="com.stewednoodles.databindingapp.Person" />
        <!--创建方法变量-->
        <variable
            name="clickHandler"
            type="com.stewednoodles.databindingapp.MyClickHandler" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/main"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{person.name}"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <!--绑定按钮点击事件
            - 使用 @{} 引入 方法变量 clickHandler
            - 使用 :: 引入 方法
        -->
        <Button
            android:onClick="@{clickHandler::onButton1Click}"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="128dp"
            android:text="Click Me!"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

3. Button 绑定事件

绑定按钮点击事件,使用 @{} 引入 方法变量 clickHandler。变量 clickHandler 与方法名 onButton1Click 之间使用::

<?xml version="1.0" encoding="utf-8"?><!--2. <layout> 作为根元素进行标记-->
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">
    <!--3. 数据绑定
         - person 变量绑定 Person 类
         - person 变量的使用方式 @{person.name}
     -->
    <data>
        <!--创建变量-->
        <variable
            name="person"
            type="com.stewednoodles.databindingapp.Person" />
        <!--创建方法变量-->
        <variable
            name="clickHandler"
            type="com.stewednoodles.databindingapp.MyClickHandler" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/main"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{person.name}"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <!--绑定按钮点击事件
            - 使用 @{} 引入 方法变量 clickHandler
            - 使用 :: 引入 方法
        -->
        <Button
            android:onClick="@{clickHandler::onButton1Click}"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="128dp"
            android:text="Click Me!"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

4. Activity 绑定事件

MainActivity 中,绑定点击事件。

package com.stewednoodles.databindingapp;

import android.os.Bundle;

import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import androidx.databinding.DataBindingUtil;

import com.stewednoodles.databindingapp.databinding.ActivityMainBinding;

public class MainActivity extends AppCompatActivity {

    //
    private ActivityMainBinding binding;
    private MyClickHandler clickHandler;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        EdgeToEdge.enable(this);
        setContentView(R.layout.activity_main);
        ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
            Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
            v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
            return insets;
        });
        // 数据实例
        Person person = new Person("Stewed Noodles", "stewednoodles.co@gmail.com");

        // 绑定数据
        binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
        binding.setPerson(person);

        // 绑定点击事件
        clickHandler = new MyClickHandler(this);
        binding.setClickHandler(clickHandler);
    }
}

5. 运行效果

运行效果,如下所示

双向绑定

BaseObservable 介绍

BaseObservable 是 Android Data Binding 提供的一个基类,让普通的 Java/Kotlin 对象具备“可观察”能力。

当对象的属性改变时,可以调用 notifyPropertyChanged() 来通知 UI 更新,无需手动 setTex() 或刷新界面。使用于

  • MVVM 中的 Model
  • 表单双向绑定
  • 需要自动刷新 UI 的 POJO 数据类

使用步骤

1. Model 继承 BaseObservable

public class User extends BaseObservable {

    private String name;

    @Bindable
    public String getName() { return name; }

    public void setName(String name) {
        this.name = name;
        notifyPropertyChanged(BR.name);
    }
}

2. 布局中绑定

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

    <TextView
        android:text="@{user.name}" />

    <EditText
        android:text="@={user.name}" /> <!-- 双向绑定 -->
</layout>

注意:布局文件中双向绑定中使用的是 @={}

示例代码

模型类 Person 的内容,如下所示

package com.stewednoodles.databindingapp;

import androidx.databinding.BaseObservable;
import androidx.databinding.Bindable;

//
public class Person extends BaseObservable {
    private String name;
    private String email;

    public Person(String name, String email) {
        this.name = name;
        this.email = email;
    }

    @Bindable
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
        notifyPropertyChanged(BR.name);
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public Person() {
    }
}

布局文件的内容,如下所示

<?xml version="1.0" encoding="utf-8"?><!--2. <layout> 作为根元素进行标记-->
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">
    <!--3. 数据绑定
         - person 变量绑定 Person 类
         - person 变量的使用方式 @{person.name}
     -->
    <data>
        <!--创建变量-->
        <variable
            name="person"
            type="com.stewednoodles.databindingapp.Person" />
        <!--创建方法变量-->
        <variable
            name="clickHandler"
            type="com.stewednoodles.databindingapp.MyClickHandler" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/main"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{person.name}"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <!--绑定按钮点击事件
            - 使用 @{} 引入 方法变量 clickHandler
            - 使用 :: 引入 方法
        -->
        <Button
            android:id="@+id/button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="128dp"
            android:onClick="@{clickHandler::onButton1Click}"
            android:text="Click Me!"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <TextView
            android:id="@+id/text_view2"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginBottom="189dp"
            android:text="@{person.name}"
            android:textSize="32sp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent" />

        <EditText
            android:text="@={person.name}"
            android:id="@+id/edit_text"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginBottom="104dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent" />
    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

最终的运行效果,如下所示

© 版权声明
THE END
喜欢就支持一下吧
点赞0赞赏 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容