Android DataBinding (一) 基本用法

本文介绍了Android DataBinding的基本概念和优势,包括如何进行环境配置、创建简单示例、理解生成的Binding类、控制类生成、使用import、include,以及Null Safe特性。详细解释了表达式的使用、双向绑定,并通过实例展示了如何减少代码耦合,提升开发效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Android DataBinding (一) 基本用法 (本文)
Android DataBinding (二) 事件处理
Android DataBinding (三) Observable
Android DataBinding (四) 自定义属性
Android DataBinding (五) 自定义 View 的双向绑定
Android DataBinding (六) EditText 绑定 TextChangedListener 和 FocusChangeListener

概述

2015 年的 I/O 大会上,Google 发布了官方的数据绑定框架 Data Binding Library,使得官方原生支持 MVVM。

Data Binding 是把数据直接绑定到 XML 文件上,并能实现自动刷新。

Data Binding 减少了代码的耦合性,一些如 findViewById、setText 之类的操作都可以通过绑定实现。

环境配置

环境配置非常简单,只要在 build.gradle 文件里面定义一下代码即可

android {
    ....
    dataBinding {
        enabled = true
    }
}

一个简单的例子

1、首先,定义一个 Java Bean

public class User {

    private String name;
    private int age;

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

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

    public void setAge(int age) {
        this.age = age;
    }
}

2、然后定义 Layout 文件

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">

    <data>

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

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

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

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{String.valueOf(user.age)}" />
    </LinearLayout>
</layout>

Layout 文件和之前有什么不同呢?

首先,在最外层再套一层 标签。

然后,在 layout 标签下面定义 标签。
data 标签下面的 variable 定义数据绑定用的实体类。这个实体是从外部传进来的(具体怎么传下文再讲)。
type 里面是完整的带包名的类,
name 自定义一个名称,下面具体绑定的时候就是用的这个名称。

最后,用 @{} 来把数据绑定到 UI 上。
@{user.name} 把 name 属性绑定到第一个 TextView 上。
@{String.valueOf(user.age)} 把 age 属性绑定到第二个 TextView 上。这里 age 是 int 类型的,所以需要把它转化成 String 类型。由于 String 是属于 java.lang 下面的,所以不需要 import。java.lang 以外的类是需要 import 的(具体怎么 import 下文再讲)。

3、数据绑定
之前的 Layout 文件的定义会默认生成一个数据绑定类,这个数据绑定类的名称默认和 Layout 文件的类名有关。比如 activity_main.xml 会生成 ActivityMainBinding.java 文件。

我们来看看代码

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
        binding.setUser(new User("Jack", 10));
    }
}

用 DatabindingUtil.setContentView() 替换之前的 setContentView(),返回值是自动生成的 ActivityMainBinding,然后调用 setUser 方法把 User 实例绑定到 XML 文件中去。

这样,运行之后就可以看到 User 的信息被显示到了画面上了。

生成的 Binding 类的获取方式

上面例子中由于是 Activity 的 Layout 文件,所以使用了 DataBindingUtil.setContentView 来获取。

除了上面的方法,还可以通过 inflate 获取。

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

如果是在 ListView 或者 RecyclerView 的 adapter 中

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

控制自动生成类的生成方式

默认情况下,会根据 XML 文件的名称(具体规则上文已经提及)在 .databinding 目录下生成文件。比如 package 名为 com.example.myapplication,那么会在 com.example.myapplication.databinding 下面生成文件。

生成的文件的名称也可以自定义。

<data class="MainBinding">
    ...
</data>

这样的话,就会在 com.example.myapplication.databinding 下面生成 MainBinding 的文件。

生成的文件的路径也可以自定义。
如果想直接在 package 下面生成

<data class=".MainBinding">
    ...
</data>

加一个 . 就会在 com.example.myapplication 下面生成 MainBinding 的文件。

当然,不想使用 package 名,想自己自定义路径,也是可以的,写全你想要的路径即可

<data class="com.example.MainBinding">
    ...
</data>

import

当在 XML 中数据绑定的时候,用到了 java.lang 之外的类,必须在 data 标签下面 import。
比如想控制 View 的显示和隐藏。

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

由于用到了 View 类,所以必须 import。

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

variable 中用到的类也可以先 import 在使用,其实和 Java 是一样的。

<data>
    <import type="com.example.tianjf.myapplication.User" />
    <variable
        name="user"
        type="User" />
</data>

如果类名相同,package 名不相同,上面的写法就会出现 type 不知道指定哪个类。但是别担心,可以用别名解决。

<data>
    <import type="com.example.tianjf.myapplication.User" alias="User1" />
    <import type="com.example.tianjf.User" alias="User2" />
    <variable
        name="user1"
        type="User1" />
    <variable
        name="user2"
        type="User2" />
</data>

import 的类型可以用到 variable 中

    <data>
        <import type="com.example.tianjf.myapplication.User" />
        <import type="java.util.List"/>
        <variable name="user" type="User"/>
        <variable name="userList" type="List<User>"/>
    </data>

import 的类型可以用到表达式中

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

import 的类型可以调用它的 static 变量和 static 方法

<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"/>

include

当 layout 文件中用到 include 的时候,variable 也可以传到 include 的 layout 文件中继续使用

<?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>

Null Safe

DataBinding 是 Null Safe 的,比如下列代码

<TextView
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:text="@{user.name}"

如果 user 为 null,@{user.name} 也将为 null,并不会出现 NullPointerException。

表达式的使用

DataBinding 的时候可以指定绑定传进来的值,也可以使用表达式达到各种效果!

前面提到的控制 View 的显示和隐藏

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

?? 操作符

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

如果不为 null,则选取 ?? 左边的,如果为 null,则选取 ?? 右边的,相当于以下代码

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

集合的使用

<data>
    <import type="android.util.SparseArray"/>
    <import type="java.util.Map"/>
    <import type="java.util.List"/>
    <variable name="list" type="List<String>"/>
    <variable name="sparse" type="SparseArray<String>"/>
    <variable name="map" type="Map<String, String>"/>
</data>
…
android:text="@{list[0]}"
…
android:text="@{sparse[0]}"
…
android:text="@{map['key']}"

Resources 的使用

DataBinding 的时候也可以使用 resources

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

Format strings 也可以使用。
比如下面的 string

<string name="name">My name is %s</string>

可以使用 String.format 传入参数

android:text="@{String.format(@string/name,user.name)}"

也可以这样写

android:text="@{@string/name(user.name)}"

双向绑定

前面介绍的都是单向绑定,即 ViewModel 的值绑定到 UI 上。如果希望 UI 的变更也反应到 ViewModel,那么就需要双向绑定了。其实双向绑定很简单,只需要加个 = 就好了。

<EditText
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="@={viewModel.firstName}"/>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值