Data Binding 用户指南(Android)

注意: 该文再也不更新,有问题请转至如下连接


1. 介绍

这篇文章介绍了如何使用Data Binding库来写声明的layouts文件,而且用最少的代码来绑定你的app逻辑和layouts文件。java

Data Binding库不只灵活并且普遍兼容- 它是一个support库,所以你能够在全部的Android平台最低能到Android 2.1(API等级7+)上使用它。android

须要:Android Studio 1.3.0-beta1 或更高版本。api

测试版本

请注意:Data Binding库当前是测试版本。在Data Binding处于测试阶段时,开发者应该了解如下注意事项:架构

  • 这是旨在生成开发者的反馈功能的测试版本。它可能包含bugs,或者不适合你的使用案例,因此须要您在使用它时自担风险。即使如此,咱们很是但愿获得您的反馈!使用issue tracker来让咱们知道对于你的使用案例什么能够工做或者不能工做。并发

  • Data Binding库的测试版本倾向于显著的改变,包括那些不是与您的应用程序兼容的源代码。即,在将来可能会进行大量的返工来更新此库。app

  • 虽然伴有标准Android SDK和Google Play服务条款适用警告,开发人员能够随时发布内置了与Data Binding库beta版本的应用程序。并且采用新的库或工具是一个至关好的主意来完全测试你的应用程序。框架

  • 咱们在这个时候才刚刚开始与Android Studio的支持。将来会有进一步的Android Studio的支持。异步

  • 经过使用Data Binding库beta版本,你认可这些警告。ide

2. 构建环境

要开始使用Data Binding,首先须要在Android SDK Manager的支持库里下载该库。

请确保您使用的是 Android Studio 的兼容版本。Android Studio的Data Binding 插件须要 Android Studio 1.3.0-beta1 或更高版本。

如下请参照最新版 - Data Binding(数据绑定)用户指南

~###工做环境~
~你的app要使用Data Binding,须要添加Data Binding到gradle构建文件里,以下:~

dependencies {
       classpath "com.android.tools.build:gradle:1.2.3"
       classpath "com.android.databinding:dataBinder:1.0-rc0"
   }
}

~而后确保jcenter在repositories列表里,以下:~

allprojects {
   repositories {
       jcenter()
   }
}

在每个你想要使用Data Binding的module,添加以下的插件:

apply plugin: ‘com.android.application'
apply plugin: 'com.android.databinding'

Data Binding插件将会在你的项目内添加必需提供的以及编译配置依赖。

3. Data Binding Layout 文件

Data Binding表达式

Data Binding layout文件有点不一样的是:起始根标签是 layout,接下来一个 data 元素以及一个 view 的根元素。这个 view 元素就是你没有使用Data Binding的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.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的变量属性,使其能够在这个layout中使用:

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

在layout的属性表达式写做@{},下面是一个TextView的text设置为user的firstName属性:

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

Data对象

假设你有一个user的plain-old Java Object(POJO):

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

这个类型的对象拥有从不改变的数据。在app中它是常见的,能够读取一次而且以后从不改变。固然也可使用JavaBeans对象:

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;
   }
}

从Data Binding的角度来看,这两个类是等价的。用于TextView中的android:text属性的表达式@{user.firstName}将访问前者POJO对象中的firstName和后者JavaBeans对象中的getFirstName()方法。

Binding数据

默认状况下,一个Binding类会基于layout文件的名称而产生,将其转换为Pascal case(译注:首字母大写的命名规范)而且添加“Binding”后缀。上述的layout文件是activity_main.xml,所以生成的类名是ActivityMainBinding。此类包含从layout属性到layout的Views中全部的bindings(例如user变量),而且它还知道如何给Binding表达式分配数值。建立bindings的最简单的方式是在inflating(译注:layout文件与Activity/Fragment的“连接”)期间以下:

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

就是这样,运行app后,你将会看到Test User。或者你能够经过以下获取View:

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

若是你在ListView或者RecyclerView adapter使用Data Binding时,你可能会使用:

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

4. 深刻 Layout 文件

Import

零个或多个import元素可能在data元素中使用。这些只用在你的layout文件中添加引用,就像在Java中:

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

如今,View可使用你的Binding表达式:

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

当类名有冲突时,其中一个类名能够重命名为alias:

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

这样,在该layout文件中Vista对应com.example.real.estate.View,而View对应android.view.View。导入的类型能够在Variable和表达式中使用做为引用来使用:

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

注意:Android Studio尚未处理imports,因此自动导入Variable在你的IDE不能使用。您的app仍会正常编译,你能够在您的Variable定义中使用彻底符合规定的名称来解决该IDE问题。

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

导入的类型还能够在表达式中使用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"/>

就像在Java中,java.lang。*是自动导入的。

Variables

data中可使用任意数量的variable元素。每个variable元素描述了一个用于layout文件中Binding表达式的属性。

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

Variable类型在编译时检查,所以若是一个Variable实现了Observableobservable collection,这应该反映在类型中。(译注:须要查找资料来理解)若是variable是一个没有实现Observable接口的基本类或者接口,Variables不会被observed!

当对于多种配置有不一样的layout文件时(如,横向或纵向),Variables会被合并。这些layout文件之间必须不能有冲突的Variable定义。

产生的Binding类对于每个描述的Variables都会有setter和getter。这些Variables会使用默认的Java值 - null(引用类型)、0(int)、false(boolean)等等,直到调用setter时。

自定义 Binding 类名称

默认状况下,Binding类的命名是基于所述layout文件的名称,用大写开头,除去下划线(_)以及(_)后的第一个字母大写,而后添加“Binding”后缀。这个类将被放置在一个模块封装包里的databinding封装包下。例如,所述layout文件contact_item.xml将生成ContactItemBinding。若是模块包是com.example.my.app,那么它将被放置在com.example.my.app.databinding

Binding类可经过调整data元素中的class属性来重命名或放置在不一样的包中。例如:

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

在模块封装包的databinding包中会生成名为ContactItem的Binding类。若是要想让该类生成在不一样的包种,你须要添加前缀.,以下:

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

在这个状况下,ContactItem类直接在模块包种生成。或者你能够提供整个包名:

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

Includes

经过使用application namespace以及在属性中的Variable名字从容器layout中传递Variables到一个被包含的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>

注意:在name.xml以及contact.xml两个layout文件中必须要有user variable

表达式

经常使用表达式跟Java表达式很像,如下这些是同样的:

  • 数学 + - / * %

  • 字符串链接 +

  • 逻辑 && ||

  • 二进制 & | ^

  • 一元运算 + - ! ~

  • 移位 >> >>> <<

  • 比较 == > < >= <=

  • instanceof

  • 分组 ()

  • null

  • Cast

  • 方法调用

  • 数据访问 []

  • 三元运算 ?:

示例:

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

缺乏的操做:

  • this

  • super

  • new

  • 显式泛型调用

Null合并操做

  • ?? - 左边的对象若是它不是null,选择左边的对象;或者若是它是null,选择右边的对象:

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

函数上的写法以下:

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

属性引用

第一个已经在前边提到了a)Data Binding表达式:JavaBean引用的简短格式。

当一个表达式引用一个类的属性,它仍使用一样的格式对于字段、getters以及ObservableFields。

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

避免 NullPointerException

Data Binding代码生成时自动检查是否为nulls来避免出现null pointer exceptions错误。例如,在表达式@{user.name}中,若是user是null,user.name会赋予它的默认值(null)。若是你引用user.age,age是int类型,那么它的默认值是0

集合

经常使用的集合:arrays、lists、sparse lists以及maps,为了简便均可以使用[]来访问。

<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>"/>
    <variable name="index" type="int"/>
    <variable name="key" type="String"/>
</data>
…
android:text="@{list[index]}"
…
android:text="@{sparse[index]}"
…
android:text="@{map[key]}"

字符串

当使用单引号包含属性值时,在表达式中使用双引号很容易:

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

使用双引号来包含属性值也是能够的。字符串先后须要使用"`":

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

Resources

使用正常的表达式来访问resources也是可行的:

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

格式化字符串和复数能够经过提供参数来判断

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

当复数须要多个参数时,全部的参数都会经过:

Have an orange
  Have %d oranges
android:text="@{@plurals/orange(orangeCount, orangeCount)}"

一些资源须要显式类型判断:

| 类型 |正常引用 | 表达式引用 |
|:-|:-|:-|
| String[] | @array | @stringArray |
| int[] | @array | @intArray |
| TypedArray | @array | @typedArray |
| Animator | @animator | @animator |
| StateListAnimator | @animator | @stateListAnimator |
| color int | @color | @color |
| ColorStateList | @color | @colorStateList |

5. Data 对象

任何Plain old Java object(PO​​JO)可用于Data Binding,但修改POJO不会致使UI更新。Data Binding的真正能力是当数据变化时,能够通知给你的Data对象。有三种不一样的数据变化通知机制:Observable对象、ObservableFields以及observable collections

当这些可观察Data对象​​绑定到UI,Data对象属性的更改后,UI也将自动更新。

Observable 对象

实现android.databinding.Observable接口的类能够容许附加一个监听器到Bound对象以便监听对象上的全部属性的变化。

Observable接口有一个机制来添加和删除监听器,但通知与否由开发人员管理。为了使开发更容易,一个BaseObservable的基类为实现监听器注册机制而建立。Data实现类依然负责通知当属性改变时。这是经过指定一个Bindable注解给getter以及setter内通知来完成的。

private static class User extends BaseObservable {
   private String firstName;
   private String lastName;
   @Bindable
   public String getFirstName() {
       return this.firstName;
   }
   @Bindable
   public String getFirstName() {
       return this.lastName;
   }
   public void setFirstName(String firstName) {
       this.firstName = firstName;
       notifyPropertyChanged(BR.firstName);
   }
   public void setLastName(String lastName) {
       this.lastName = lastName;
       notifyPropertyChanged(BR.lastName);
   }
}

在编译期间,Bindable注解在BR类文件中生成一个Entry。BR类文件会在模块包内生成。若是用于Data类的基类不能改变,Observable接口经过方便的PropertyChangeRegistry来实现用于储存和有效地通知监听器。

Observable 字段

一些小工做会涉及到建立Observable类,所以那些想要节省时间或者几乎没有几个属性的开发者可使用ObservableFieldsObservableFields是自包含具备单个字段的observable对象。它有全部基本类型和一个是引用类型。要使用它须要在data对象中建立public final字段:

private static class User extends BaseObservable {
   public final ObservableField<String> firstName =
       new ObservableField<>();
   public final ObservableField<String> lastName =
       new ObservableField<>();
   public final ObservableInt age = new ObservableInt();
}

就是这样,要访问该值,使用set和get方法:

user.firstName.set("Google");
int age = user.age.get();

Observable 集合

一些app使用更多的动态结构来保存数据。Observable集合容许键控访问这些data对象。ObservableArrayMap用于键是引用类型,如String

ObservableArrayMap<String, Object> user = new ObservableArrayMap<>();
user.put("firstName", "Google");
user.put("lastName", "Inc.");
user.put("age", 17);

在layout文件中,经过String键能够访问map:

<data>
    <import type="android.databinding.ObservableMap"/>
    <variable name="user" type="ObservableMap<String, Object>"/>
</data>
…
<TextView
   android:text='@{user["lastName"]}'
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"/>
<TextView
   android:text='@{String.valueOf(1 + (Integer)user["age"])}'
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"/>

ObservableArrayList用于键是整数:

ObservableArrayList<Object> user = new ObservableArrayList<>();
user.add("Google");
user.add("Inc.");
user.add(17);

在layout文件中,经过索引能够访问list:

<data>
    <import type="android.databinding.ObservableList"/>
    <import type="com.example.my.app.Fields"/>
    <variable name="user" type="ObservableList<Object>"/>
</data>
…
<TextView
   android:text='@{user[Fields.LAST_NAME]}'
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"/>
<TextView
   android:text='@{String.valueOf(1 + (Integer)user[Fields.AGE])}'
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"/>

6. Binding生成

Binding类的生成连接了layout中variables与Views。如前面所讨论的,Binding的名称和包名能够定制。所生成的Binding类都扩展了android.databinding.ViewDataBinding

建立

Binding应在inflation以后就立马建立,以确保View层次结构不在以前打扰layout中的binding到views上的表达式。有几个方法能够绑定到一个layout。最多见的是在Binding类上使用静态方法.inflate方法载入View的层次结构而且绑定到它只需这一步。还有一个更简单的版本,只须要LayoutInflater还有一个是采用ViewGroup

MyLayoutBinding binding = MyLayoutBinding.inflate(layoutInflater);
MyLayoutBinding binding = MyLayoutBinding.inflate(LayoutInflater, viewGroup, false);

若是使用不一样的机制载入layout,他可一分开绑定:

MyLayoutBinding binding = MyLayoutBinding.bind(viewRoot);

有时Binding不能提早知道,对于这种状况,可使用DataBindingUtil类来建立Binding:

ViewDataBinding binding = DataBindingUtil.inflate(LayoutInflater, layoutId,
    parent, attachToParent);
ViewDataBinding binding = DataBindingUtil.bindTo(viewRoot, layoutId);

带ID的Views

在layout中对于每一个带ID的View会生成一个public final字段。Binding在View层次结构上作单一的传递,提取带ID的Views。这种机制比起某些Views使用findViewById还要快。例如:

<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}"
   android:id="@+id/firstName"/>
       <TextView android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:text="@{user.lastName}"
  android:id="@+id/lastName"/>
   </LinearLayout>
</layout>

它会生成以下的Binding类:

public final TextView firstName;
public final TextView lastName;

IDs不像没有Data Bindings那样几乎没有必要,可是仍然会有一些实例须要从代码中访问Views。

Variables

每一个Variable会有访问方法。

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

它会在Binding中生成setters和getters:

public abstract com.example.User getUser();
public abstract void setUser(com.example.User user);
public abstract Drawable getImage();
public abstract void setImage(Drawable image);
public abstract String getNote();
public abstract void setNote(String note);

ViewStubs

ViewStubs跟正常的Views略有不一样。他们开始时是不可见的,当他们要么设置为可见或被明确告知要载入时,它们经过载入另一个layout取代了本身。

因为ViewStub基本上从View的层次结构上消失,在Binding对象的View也必须消失来容许被收集。由于Views是最后的,一个ViewStubProxy对象取带ViewStub,给开发者得到了ViewStub,当它存在以及还能够访问载入的View层次结构时当ViewStub已被载入时。

当载入另外一个layout,为新的布局必需建立一个Binding。所以,ViewStubProxy必需监听ViewStubOnInflateListener监听器并在那个时候创建Binding。由于只有一个能够存在,ViewStubProxy容许开发者在其上设置一个OnInflateListener它会在创建Binding后调用。

Binding进阶

动态Variables

有时,不知道具体的Binding类,例如,一个RecyclerView适配器对layouts任意操做并不知道具体的Binding类。它仍然必需在onBindViewHolder期间赋值给Binding。

在这个例子中,该RecyclerView绑定的全部layouts有一个“item”的Variable。该BindingHolder有一个getBinding方法返回ViewDataBinding

public void onBindViewHolder(BindingHolder holder, int position) {
   final T item = mItems.get(position);
   holder.getBinding().setVariable(BR.item, item);
   holder.getBinding().executePendingBindings();
}

直接Binding

当一个variable或observable变化时,binding会在下一帧以前被计划要改变。有不少次,可是在Binding时必须当即执行。要强制执行,使用executePendingBindings()方法。

后台线程

只要它不是一个集合,你能够在后台线程中改变你的数据模型。在判断是否要避免任何并发问题时,Data Binding会对每一个Varialbe/field本地化。

7. 属性Setters

每当绑定值的变化,生成的Binding类必须调用setter方法​​。Data Binding框架有能够自定义赋值的方法。

自动Setters

对于一个属性,Data Binding试图找到setAttribute方法。与该属性的namespace并不什么关系,仅仅与属性自己名称有关。

例如,有关TextView的android:text属性的表达式会寻找一个setText(String)的方法。若是表达式返回一个int,Data Binding会搜索的setText(int)方法。注意:要表达式返回正确的类型,若是须要的话使用casting。Data Binding仍会工做即便没有给定名称的属性存在。而后,您能够经过Data Binding轻松地为任何setter“创造”属性。例如,DrawerLayout没有任何属性,但大量的setters。您可使用自动setters来使用其中的一个。

<android.support.v4.widget.DrawerLayout
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:scrimColor="@{@color/scrim}"
    app:drawerListener="@{fragment.drawerListener}"/>

重命名的Setters

一些有setters的属性按名称并不匹配。对于这些方法,属性能够经过BindingMethods注解相关联。这必须与一个包含BindingMethod注解的类相关联,每个用于一个重命名的方法。例如,android:tint属性与setImageTintList相关联,而不与setTint相关。

@BindingMethods({
       @BindingMethod(type = "android.widget.ImageView",
                      attribute = "android:tint",
                      method = "setImageTintList"),
})

以上例子,开发者须要重命名setters是不太可能了,android架构属性已经实现了。

自定义Setters

有些属性须要自定义绑定逻辑。例如,对于android:paddingLeft属性并无相关setter。相反,setPadding(left, top, right, bottom)是存在在。一个带有BindingAdapter注解的静态绑定适配器方法容许开发者自定义setter如何对于一个属性的调用。

Android的属性已经创造了BindingAdapters。举例来讲,对于paddingLeft

@BindingAdapter("android:paddingLeft")
public static void setPaddingLeft(View view, int padding) {
   view.setPadding(padding,
                   view.getPaddingTop(),
                   view.getPaddingRight(),
                   view.getPaddingBottom());
}

Binding适配器对其余定制类型很是有用。例如,自定义loader能够用来异步载入图像。

当有冲突时,开发人员建立的Binding适配器将覆盖Data Binding默认适配器。

您也能够建立能够接收多个参数的适配器。

@BindingAdapter({"bind:imageUrl", "bind:error"})
public static void loadImage(ImageView view, String url, Drawable error) {
   Picasso.with(view.getContext()).load(url).error(error).into(view);
}
<ImageView app:imageUrl=“@{venue.imageUrl}”
app:error=“@{@drawable/venueError}”/>

若是对于一个ImageViewimageUrlerror都被使用而且imageUrl是一个string类型以及error是一个drawable时,该适配器会被调用。

  • 匹配的过程当中自定义namespaces将被忽略。

  • 你也能够为Android namespaces写适配器。

8. 转换

对象转换

当从Binding表达式返回一个对象,一个setter会从自动、重命名以及自定义的setters中选择。该对象将被转换为所选择的setter的参数类型。

这是为了方便那些使用ObservableMaps来保存数据。例如:

<TextView
   android:text='@{userMap["lastName"]}'
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"/>

userMap返回一个对象而且该对象将自动转换为setText(CharSequence)的参数类型。当有关参数类型可能混乱时,开发人员须要在表达式中转换。

自定义转换

有时候转换应该是自动的在特定类型之间。例如,设置背景的时候:

<View
   android:background="@{isError ? @color/red : @color/white}"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"/>

这里,背景须要Drawable对象,但颜色是一个整数。无论什么时候有Drawable而且返回值是一个整数,那么整数类型会被转换为ColorDrawable。这个转换是经过使用带有BindingConversion注解的静态方法完成的:

@BindingConversion
public static ColorDrawable convertColorToDrawable(int color) {
   return new ColorDrawable(color);
}

注意:转换仅仅发生在setter级别,所以它是不容许如下混合类型:

<View
   android:background="@{isError ? @drawable/error : @color/white}"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"/>

---------------------<完>-----------------------

(若有翻译有误或者不理解的地方,请指正)

原文连接:Data Binding Guide (Android)
译者:田浩浩@DockOne