美文网首页Android Devandroid收集android干货
Android Data Binding(数据绑定)用户指南

Android Data Binding(数据绑定)用户指南

作者: llitfk_DockOne | 来源:发表于2015-06-04 14:55 被阅读55631次

    1)介绍

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

    Data Binding库不仅灵活而且广泛兼容- 它是一个support库,因此你可以在所有的Android平台最低能到Android 2.1(API等级7+)上使用它。

    需求:Android Plugin for Gradle **1.5.0-alpha1 **或 更高版本

    2)构建环境

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

    你的app要使用Data Binding,需要添加Data Binding到gradle构建文件里,如下:

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

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

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

    3)Data Binding Layout文件

    a)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}"/>
    
    b)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()方法。

    c)Binding数据

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

    @Override
    protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       MainActivityBinding 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);
    
    d)事件处理

    数据绑定允许你编写表达式来处理view分派的事件。事件属性名字取决于监听器方法名字。例如View.OnLongClickListeneronLongClick()的方法,因此这个事件的属性是android:onLongClick。处理事件有两种方法:

    4)深入Layout文件

    a)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。*是自动导入的。

    b)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时。

    c)自定义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>
    
    d)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

    e)表达式
    • 常用表达式跟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也将自动更新。

    a)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来实现用于储存和有效地通知监听器。

    b)Observable 字段

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

    private static class User {
       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();
    
    c)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

    a)创建

    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);
    
    b)带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。

    c)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);
    
    d)ViewStubs

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

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

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

    e)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框架有可以自定义赋值的方法。

    a)自动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}"/>
    
    b)重命名的Setters

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

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

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

    c)自定义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)转换

    a)对象转换

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

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

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

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

    b)自定义转换

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

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

    9)Android Studio支持

    Android Studio为数据绑定支持许多的代码编辑。例如,它支持以下功能:

    注意: 数组以及通用类型,比如说Observable类,可能会显示错误事实上并没有错误。

    预览面板会显示数据绑定的默认值。在以下例子中,面板会在TextView中显示PLACEHOLDER默认值

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

    如果你需要在设计阶段就显示默认值,你可以使用工具属性来代替默认表达数值,参考:Designtime Layout Attributes

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

    原文链接:Data Binding Guide (Android)

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


    Github参考示例

    MasteringAndroidDataBinding@LyndonChin
    感谢@liangfeizc的推荐


    译者:田浩浩@DockOne

    邮箱:llitfkitfk@gmail.com

    相关文章

      网友评论

      • 361579c6b5ba:MainActivityBinding怎么写的呀?
        361579c6b5ba:的确如此,多谢多谢。
        cyixlq:自动生成的,根据你的布局文件的名字加Binding生成。例如,你的布局文件名字是activity_main.xml,那么自动生成的文件名就是ActivityMainBinding。下划线之后首字母和文件名首字母为大写,同时去掉下划线!
      • _孑孓_:翻译的有点蛋疼,不过精神可嘉
        llitfk_DockOne:@SpritMoon :joy:
      • 1afc7c6c95e3:为什么用了databinding,代码里还是在用findViewById??????????
      • 朵蓝梦:非常感谢!
        llitfk_DockOne:多谢支持
      • f6770040b41e:楼主你好,请教给问题webview怎么使用 databinding loadurl
      • RZWP:无意测试了下死循环中执行 binding.setXXX ,结果没有刷新UI, 楼主能给指明一下吗?
        去除死循环倒是可以执行1次...
        @Override
        protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        final ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
        final User user = new User("张三", 24, "北京市");
        binding.setUser(user);
        binding.getRoot().postDelayed(new Runnable() {
        @Override
        public void run() {
        while (true) {
        try {
        Thread.sleep(1000);
        } catch (InterruptedException e) {
        e.printStackTrace();
        }
        user.setAge(user.getAge() + 1);
        binding.setUser(user);
        }
        }
        }, 3000);
        }
      • 0532711f24d1:混淆文件如何处理
      • Ashen_:很感谢楼主不辞辛劳的翻译, 获益匪浅. 这里有个问题请指教一下. 1.这个binding的意思是不是是一旦修改属性user.setName = "aName", 会直接反映到界面上? 而不需要再调用aBind.setUser(user); 我用这种方式发现没有更新界面, 是我对binding的理解错了吗?
        llitfk_DockOne:@石_阿神 setmName 怎么写的
        Ashen_:@田浩浩_DockOne public class MainActivity extends AppCompatActivity {

        com.shmilyanddroid.sj.databinding.CustomBinding aBind;
        int aValue = 0;

        User user;

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

        setContentView(R.layout.activity_main);
        aBind = DataBindingUtil.setContentView(this,R.layout.activity_main);
        user = new User("初始化1","初始化2");
        aBind.setUser(user);

        Button aBtn = (Button) findViewById(R.id.mButton1);
        aBtn.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {

        user.setmName("监控值" + aValue);
        aValue++;
        }
        });
        }
        }

        这个应该没问题吧? 怎么效果出不来,求指教
        llitfk_DockOne:@石_阿神 没有更新 可能是user.setName = “aName” 的user 不是 binding的User
      • neumeng:activity_main和main_activity分不清楚了 :scream:
        llitfk_DockOne:@neumeng 已修正
      • c1e32702d55e:为什么我在使用的时候找不到类ListItemBinding
        llitfk_DockOne:@拂晓之前 请贴下日志
      • lishiwei:比自己翻译 快多了。。。
      • 带心情去旅行:原文:Android Plugin for Gradle 1.5.0-alpha1 or higher is required.说的是gradle的版本,并不是Android的版本把?
        文中:Android Studio 1.5.0-alpha1 或 更高版本
        llitfk_DockOne:@带心情去旅行 已修改
        感谢支持
      • 这时对那时错:ObservableArrayList 键是整数0-0什么意思 list哪有键啊
        llitfk_DockOne:@这时对那时错 原文上是这样写的,最佳实践可以参考github链接里的项目
      • 螃蟹钓鱼:<variable name="userList" type="List<User>"/>
        不能直接这么写,要用转义字符
        llitfk_DockOne:@螃蟹钓鱼 已更新
        thx
      • ce8379ec301a:“Observable字段”一节中,代码和官方文档不一样,官方文档中User没有继承BaseObservable
        llitfk_DockOne:@张三思 多谢指正, 已修改
      • fancychendong:我发现如果用android gradle tool 的版本是 2.0.0-alpha的时候,生成的是1.1.0的databinding依赖文件,但不全;而改用 1.5.0可以生成出1.0.0-rc版本的databinding,没任何问题。我用的as也是2.0 preview4的,请问有人遇到这个问题吗?
        另外 1.0.0-rc版本的是不是属于不稳定的版本,现在databinding到底有没有稳定下来,如果稳定了以后开发android将是另外全新的方式了~~~变化好大,有什么看法
      • fancychendong:好人啊,本来也想翻译下的,但是看到有简友已经翻译好了,十分感谢!
      • Hanwen1001:现在在 Module中加入下面这个就可以了!
        android {
        ....
        dataBinding {
        enabled = true
        }
        }
        沙滩上玩耍的孩纸:请问楼主,为什么我在设置bing.setModel()为什么一直报错
        llitfk_DockOne:@HanWen 多谢!
        已修改
      • a882c12bca8e:博主,配置的时候遇到一些 问题,一直卡在debug_compleshang,取消后出现:
        Error:Could not run build action using Gradle installation 'D:\android-studio\gradle\gradle-2.8'.错误,求教如何正确配置
      • __Berial___:翻译成中文十分感人,但是有些地方的翻译比较生硬,理解不能啊。总是,还是感谢楼主
        llitfk_DockOne:@__Berial___
        感谢支持,翻译上以后会多多练习并加以修正
        不是专业翻译出身,做这个事情只为了造福那些对英文文档不是很喜欢,但对新技术又很痴迷的程序猿们
      • llitfk_DockOne:@liangfeizc 已加入豪华套餐
      • 老梁写代码:不错不错,我根据这篇介绍文档写了很多samples,有兴趣的同学可以结合代码一起看
        https://github.com/LyndonChin/MasteringAndroidDataBinding
        llitfk_DockOne:@liangfei 能在github readme的原文链接处加个该翻译文章的链接么?
      • 字字珠玑:楼主的排版太好了,是用简书的markdown编辑器写的这篇文章吗
      • 屠龙:@脉脉不得语 好的,谢谢哈
      • 屠龙:@田浩浩_DockOne 为啥我的检测不到?我只能检测到.AndroidStudioPreview1.3版本的
      • llitfk_DockOne:@屠龙 在Canary Channel更新
      • 屠龙:表示Android Studio 1.3.0-beta1在哪?貌似买有找到beta版
      • Holyn:牛

      本文标题:Android Data Binding(数据绑定)用户指南

      本文链接:https://www.haomeiwen.com/subject/bisdqttx.html