8、DataBinding表达式与运算符:三元运算符、空合并运算符、集合与数组访问、字符串拼接与格式化

DataBinding 的表达式语法,说白了就是让你在 XML 里写逻辑。很多人刚接触时觉得别扭——「逻辑不该写在 Java/Kotlin 里吗?」我刚开始也这么想。但用久了你会发现,有些简单的 UI 判断,写在 XML 里反而更清爽,不用在代码里写一堆 if-else 和 findViewById。

这一节我们聊几个最常用的运算符和表达式。它们不复杂,但用好了能省不少事。

8.1 三元运算符:最简单的条件判断

三元运算符是 DataBinding 里最常用的条件表达式。格式很简单:条件 ? 真值 : 假值

<TextView
    android:text="@{user.isVIP ? "VIP用户" : "普通用户"}"
    android:textColor="@{user.isVIP ? @color/gold : @color/gray}" />

我个人习惯把三元运算符用在颜色、文字、可见性这类简单切换上。比如用户头像的占位符:

<ImageView
    android:src="@{user.avatar != null ? user.avatar : @drawable/ic_default_avatar}" />
小技巧: 三元运算符可以嵌套,但别超过两层。三层以上可读性就崩了,不如拆到 ViewModel 里。

8.2 空合并运算符:告别空指针

Kotlin 开发者对 ?? 肯定不陌生。DataBinding 里同样支持这个运算符。它的作用是:左边不为空就用左边,否则用右边。

<TextView
    android:text="@{user.nickname ?? "未设置昵称"}" />

这比写三元运算符 user.nickname != null ? user.nickname : "未设置昵称" 简洁多了。

我曾经在一个列表页里忘了处理空值,结果用户昵称为 null 时,TextView 直接显示了一行 "null"。嗯,那个版本上线后被吐槽了。后来我养成了习惯——所有展示用户输入字段的地方,都加上 ?? 兜底。

注意: 空合并运算符只检查 null,不检查空字符串。如果字段可能是空字符串,你仍然需要三元运算符:@{(user.nickname != null && !user.nickname.isEmpty()) ? user.nickname : "未设置"}

8.3 集合与数组访问:拿数据就这么简单

DataBinding 支持通过下标访问 List、Array 和 Map。语法和 Kotlin 一样:

<!-- List 或 Array -->
<TextView android:text="@{list[0]}" />
<TextView android:text="@{array[position]}" />

<!-- Map -->
<TextView android:text="@{map["key"]}" />
<TextView android:text="@{map[user.keyField]}" />

我在项目中遇到过这样一个场景:一个商品详情页需要展示规格列表,用户选中某个规格后,价格区域要同步更新。用 DataBinding 的集合访问就很方便:

<TextView
    android:text="@{"¥" + specList[selectedIndex].price}" />

你想想看,如果没有 DataBinding,你得写多少代码?先拿到 List,再根据下标取值,再 setText……现在一行搞定。

核心要点: 集合下标可以是变量,比如 @{list[viewModel.currentIndex]}。只要变量变化,UI 会自动刷新。

8.4 字符串拼接与格式化

字符串拼接在 DataBinding 里用 + 号就行。但要注意——所有非字符串类型需要显式转换:

<!-- 正确 -->
<TextView android:text="@{"用户:" + user.name + ",年龄:" + String.valueOf(user.age)}" />

<!-- 错误:age 是 int,不能直接拼接 -->
<!-- android:text="@{"年龄:" + user.age}" -->

格式化字符串我推荐用 @string 资源配合占位符。这样更干净,也方便做国际化:

<!-- strings.xml -->
<string name="user_info">用户名:%s,积分:%d</string>

<!-- layout.xml -->
<TextView
    android:text="@{@string/user_info(user.name, user.points)}" />

这种写法比在 XML 里拼一大串要优雅得多。我个人的习惯是:超过两个变量的拼接,一律用 @string 格式化。

8.5 知识体系一览

下面这张图把本节涉及的运算符和表达式串了起来。你可以把它当作速查表:

DataBinding 表达式与运算符 三元运算符 条件 ? 真值 : 假值 颜色/文字/可见性切换 可嵌套,但别超过2层 空合并运算符 左边 ?? 右边 左边非空用左边 否则用右边兜底 集合与数组 list[0] / map["key"] 支持变量作为下标 数据变化自动刷新 字符串拼接 "前缀" + 变量 非String需显式转换 推荐@string格式化 ⚠️ 常见坑点 • 空合并运算符只检查 null,不检查空字符串 • 字符串拼接时,int/boolean 等类型需要 String.valueOf() 转换 • 三元运算符嵌套超过2层时,建议抽取到 ViewModel 中

8.6 实战组合:一个完整的例子

把上面这些知识点串起来,看看实际页面怎么写。假设我们要展示一个商品卡片:

<layout>
    <data>
        <variable name="product" type="com.example.Product" />
        <variable name="isLoggedIn" type="boolean" />
    </data>
    
    <LinearLayout>
        <!-- 商品名称,没有则显示默认文案 -->
        <TextView
            android:text="@{product.name ?? "未知商品"}" />
        
        <!-- 价格,VIP用户显示金色 -->
        <TextView
            android:text="@{"¥" + String.valueOf(product.price)}"
            android:textColor="@{product.isVIP ? @color/gold : @color/red}" />
        
        <!-- 标签列表,取第一个标签展示 -->
        <TextView
            android:text="@{product.tags != null && product.tags.size() > 0 ? product.tags[0] : ""}" />
        
        <!-- 购买按钮,未登录显示灰色 -->
        <Button
            android:enabled="@{isLoggedIn}"
            android:text="@{isLoggedIn ? "立即购买" : "请先登录"}" />
    </LinearLayout>
</layout>

这个例子涵盖了本节所有知识点。你仔细看——没有一行 Java/Kotlin 代码,所有 UI 逻辑都在 XML 里完成了。这就是 DataBinding 表达式的魅力。

我的建议: 表达式里如果出现复杂的逻辑判断(比如多个条件组合),还是放到 ViewModel 里用 @Bindable 暴露出来。XML 里只做简单的取值和判断,这样维护起来更轻松。

好了,这一节的内容就这些。运算符和表达式是 DataBinding 的基础能力,掌握了它们,你就能写出更简洁、更声明式的布局文件。下一节我们会聊更高级的话题——双向绑定,到时候你会发现,原来数据和 UI 可以配合得这么默契。


公众号:蓝海资料掘金营,微信deep3321