Android Jetpack 系列(二)Data Binding 核心功能与实践

1. 简介

回顾我们在前文《Android 界面库 (一) 之 View binding 简单使用》中学习的 View Binding,这种技术旨在简化 View 与代码之间的绑定过程。View Binding 会在编译时为每个 XML 布局文件生成相应的绑定类(Binding class),该类包含了布局文件中每个有 ID 的 View 的引用,从而避免了频繁手动调用 findViewById() 方法获取 View 对象。

本篇文章将介绍 View Binding 的进阶版本——Data Binding。Data Binding 也是 Android Jetpack 库的一部分,它不仅会在编译时为布局文件生成相应的绑定类,还具有在布局中绑定数据的高级功能。

Data Binding 通常用于将 UI 布局元素与逻辑端的数据模型建立连接,从而使 UI 元素能够自动与数据模型的值进行同步更新,实现 UI 与数据的绑定。通过这种方式,开发者可以更专注于数据和业务逻辑,而无需过多关注 UI 的更新。

2. 启用 Data binding

如果需要在工程项目中启用Data binding,需要先在项目模块级 buid.gradle 文件中将 dataBinding 构建选项设置为 true, 如:

android {
    ...
    buildFeatures {
        dataBinding true
    }
}

3. 使用

3.1. XML布局

Data binding 的 XML 布局文件跟常规布局文件略有不同,Data binding 布局的根标记以 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.name}"/>
       <TextView android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:text="@{ String.valueOf (user.age)}"/>
   </LinearLayout>
</layout>

其中,data 中的 variable 用于在布局中定义变量,这里的变量是 com.example.User 类型的 user。即示例中:

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

布局中的表达式使用 @{} 语法写入属性。即示例中:

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

提示:文章下方会详细介绍变量和表达式。

Android Studio自动转成 Data binding布局:

当你将鼠标移到布局文件中的根元素时,会出现一个黄色灯提示悬浮按钮,点击它然后选择Convert to data binding layout,那么 Android Studio 会把常规布局自动转成 Data binding 绑定布局。如下图所示:

3.2. 布局的变量

如上述示例,在布局文件中的 data 元素里的 variable 元素就是用于定义布局上的变量。variable 元素可以有多个,它可以在布局文件中的绑定表达式中使用。示例: 

<data>
    <variable name="user" type="com.example.User"/>
    <variable name="name" type="String"/>
    <variable name="age" type="int"/>
</data>

注意:如果存在多种配置(例如横向或纵向)有不同的布局文件,系统会合并变量。这些布局文件之间不能有冲突的变量定义。

3.2.1 导入类包

在布局文件中的 data 元素里,可以像 Java/Ktolin 代码导入包一样使用 import 来导入引用类,示例:

<data>
    <import type=" com.example.User "/>
    <import type="java.util.List"/>
    <import type="android.view.View"/>
    <import type="com.example.real.estate.View" alias="Vista"/>
    <import type="com.example.MyStringUtils"/>

    <variable name="user" type=" User"/>
    <variable name="userList" type="List&lt;User>"/>
</data>
  1. 通过导到入了 User 类,那么在下面的 variable 元素定义变量时便可以不再使用完整的类名;
  2. 通过导入 View 类,便可以从下方绑定表达式中引用该类。例如使用 View 类的 VISIBLE 和 GONE 常量:
  3. 当导入的类名冲突时,还可以使用 alias 来给导入的类重命名,然后便可以在布局文件中使用重命名后的类名来引用它字段或方法;
  4. 还可以导入某一个类,然后在表达式中使用该类的静态方法。

使用导入类的表达式示例:

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

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

3.2.2 传递变量给子布局

你可以将变量从包含布局传递到所含子布局的绑定中,方法是在属性中使用应用命名空间和变量名称。示例:

activity_main.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_layout"  bind:user="@{user}"/>
   </LinearLayout>
</layout>

name_layout.xml

<?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
       ……
   </LinearLayout>
</layout>

示例中在 activity_main.xml 通过 bind:user="@{user}" 将 user 变量传递到 name_layout.xml布局文件中,这样就可以在name_layout.xml布局中也使用user变量。

注意:在主布局和子布局中,变量名称和类型必须一致。否则,数据绑定将无法识别并传递变量。

特别注意:Data binding不支持 include 作为 merge 元素的直接子元素。例如以下是一个错误的示例:

<?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_layout"  bind:user="@{user}"/>
   </merge>
</layout>

3.3. 布局的表达式

如上述示例,在布局 View 中使用的 @{…},便是布局中的表达式。布局表达式有它自己的语言规则,例如它能支持运算符和一些特定的关键字。

3.3.1. 常见表达式运算符和关键字

类型

操作符

数字

+ - / * %

字符串串联

+

逻辑

&& ||

二进制文件

& | ^

二进制位移

>> >>> <<

一元组

+ - ! ~

比较

== > < >= <= (“<”是XML语法关键字,所以需要转义为 &lt;)

数组访问

[ ]

三元运算符

?: (跟Java中的“?:” 一样用法,用作条件判断后选择)

Null 合并

?? (跟Kotlin中的“?:”一样用法,用作前值为空时使用后值)

示例:

android:text="@{String.valueOf(index + 1)}"
android:visibility="@{age > 18 ? View.GONE : View.VISIBLE}"
android:transitionName='@{"image_" + id}'
android:text="@{user. firstName ?? user.lastName}"
android:text="@{user. firstName != null ? user. firstName: user.lastName}"

注意:任何在布局中的表

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值