Android Data Binding 数据绑定技术导读

DataBinding使用教程(三):各个注解详解 文章有点长,请做好心理准备 有哪些注解 @Bindable @BindingAdapter @BindingBuildInfo @BindingConversion @BindingMethod @BindingMethods @InverseBindingAdapter @InverseBindingMethod @InverseBindingMethods @InverseMetho... 阅读详情

 

       这篇文档会解释如何使用数据绑定库来为应用程序的逻辑和布局编写声明式布局和最小化必需的胶水代码。

 

        数据绑定库提供了灵活性和广泛的兼容性——他是一个支持库,因此你可以使用最低到Android 2.1平台(API 级别7以上)上。

        

         AndroidStudio的版本需要在1.3.0-beta1以上。

        

这是一个Beta发布版

         请注意,数据绑定库当前处于beta版本。当数据绑定技术处于beta版本时期,开发者应该遵守以下注意事项:

         *这是一个beta发布版本,因此会生成开发者反馈数据,这些数据会包含一些bug,对你的用例没啥用处,所以需要自担风险。也就是说,我们需要你的反馈!请让我们了解有什么好用还有什么不好用。请使用问题跟踪 issue tracker.

         *数据绑定beta发布版有显著的变化,包括那些没有和你的应用相兼容的源代码,这意味着在将来更新以后会有更多的重复修改的工作。

         *开发者会感到使用数据绑定库beta版构建应用很自由,只要遵守标准Android SDK和Google Play应用服务条款,并且在使用新的库或者工具的时候进行彻底的测试是个不错的主意。

         *我们现在刚刚开始对AndroidStudio的支持工作。Android Studio的支持会在不久以后逐渐释出。

         *通过使用数据绑定库beta版,你需要遵守这些注意事项。

 

搭建环境

         要开始使用数据绑定库,首先需要从AndroidSDK管理器下载支持仓库。确保你使用的是Android Studio功能可用的版本。数据绑定插件需要在Android Studio 1.3.0-beta1或者更高的版本。

 

设定工作环境

 

要设定你的应用可以使用数据绑定技术,添加数据绑定到类包含路径中,需要修改build.gradle文件,在“android”下添加如下代码:

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

 

然后要确保jcenter在子项目的仓库列表中

 

allprojects {
   repositories {
       jcenter()
   }
}

 

在每个Module中你希望使用数据绑定,需要应用插件。

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

数据绑定插件将会添加有必要的设置和依赖项目的编译配置。

 

数据绑定布局文件

编写你的第一个数据绑定表达式

数据绑定布局文件会有一点不太一样,它有一个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.firstName}"/>        <TextView  android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:text="@{user.lastName}"/>    </LinearLayout> </layout>

在数据中的用户变量所描述的成员中,可以在布局文件中使用。

 

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

布局中的表达式都是写在使用“@{}”语法的属性的成员中。在这里,TextView的本文会被设定到user的firstName成员中。(这里本应该不应该翻译成成员,但是有attribute和properties都翻译成属性,这两个词却在这里有不同的意义,因此properties在这里被引申为member的含义)。

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

 

数据对象

让我们假设现在你有一个普通的Java对象(POJO)叫做User:

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

这个类型的对象有数据,但是不会更改。应用程序中一般做法是存储数据而后不再更改。那么也就有可能使用一个JavaBean对象了:

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

从数据绑定的角度看,这两个类其实是等价的。表达式@{user.firstName} 用作TextView的android:text属性,在前面这个类当中将可以访问到firstName这个变量域,而在后面这个类当中会使用 getFirstName() 方法。

 

绑定数据

默认情况下,一个绑定类会生成基于名称的布局文件,转换成Pascal(??),并且后缀上去。上面的布局文件是activity_main.xml ,因此会生成类是 ActivityMainBinding. 这个类持有所有从布局文件中相应的View对应的属性(例如:user变量),并且知道如何指派变量值到绑定的表达式中。创建绑定的最简单方法是在扩展布局生成视图的时候做:

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

这就完事了!运行一下应用程序你会看到UI界面上的测试User。当然,这也是可以通过如下方式替换的:

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

如果你在使用ListView(列表视图)或者RecyclerView(回收器视图)进行数据绑定,你可以通过如下方式获取View的实例:

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

数据绑定布局详解

导入包

在data元素中,可以有大于等于0个import元素。这些元素可以让你轻松的引用在你的布局文件中,就像Java

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

现在View可以在绑定表达式中使用了

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

这样的话,Vista可以用来引用com.example.real.estate.View 而View仍然在布局文件中引用android.view.View 。导入类型可以在变量和表达式中作为类型引用。

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

注意:Android Studio尚且不能处理导入路径,因此为导入变量的自动完成功能在你的IDE中不能工作。你可以绕开这些IDE的问题在你的变量定义中使用完全限定的名称。

 

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

 

导入类型也可以在绑定表达式中用作引用静态变量域和方法

 

<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.* 包会自动导入。

 

变量

在data元素中,可以使用任意数量的 variable 元素。每一个 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>

变量类型会在编译时受到检查,所以如果一个变量实现了Observable (可被观察特性),或者是一个观察者集合,它会进行类型反射。如果一个变量是一个基类或者接口,并且么有实现Observable接口,这个变量将不会被监视。

 

当有不同的布局文件有多种配置的时候(例如横屏或者竖屏),这些变量会被联合。这些布局文件中不能有变量定义的冲突。

 

生成的绑定类会为每一个变量提供一个setter和getter。这些变量会使用Java中的默认值直到使用setter调用——null为引用类型的默认值,0为int默认值,false是boolean的默认值等。

 

自定义的绑定类名称

·默认情况下,一个绑定类是根据布局文件的名字生成的,开头大写,移除下划线“_”,然后使用后面的字母,然后加上“Binding”后缀。这个类将会被放置在模块包中的数据绑定包。

比如,布局文件contact_item.xml 会生成ContactItemBinding类。如果模块包是com.example.my.app,那么将会被放置到com.example.my.app.databingding中。

绑定类会通过调整data元素的class属性对应被重新命名或者放到不同的包中。

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

这种情况下, ContactItem 会在模块包中直接生成。如果提供了一个完整的包名,任何包都可能被使用。

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

包含布局

变量可以通过使用应用命名空间和属性变量名从绑定的包含布局传给一个被包含的布局中:

<?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 中一定都要有一个 user 变量。

 

表达式语言

通用特性

表达式语言看起来很像Java表达式。这些是相同的:

·        数学符号+ - / * %

·        字符串连接 +

·        逻辑运算符 && ||

·        二进制位运算符 & | ^

·        单目运算符 + - ! ~

·        移位运算 >> >>> <<

·        比较运算符 == > < >= <=

·        Instanceof实例断言

·        括号分组 ()

·        文字 – 字母, 字符串, 数字类型, null

·        强制类型转换

·        方法调用

·        变量域访问

·        数组元素访问 []

·        三目运算符 ?:

例如:

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

不可用的操作符

表达式中有少量Java中可用的操作是缺失的

·        this

·        super

·        new

·        声明式调用

空安全运算符

空安全运算符(??)会当左操作数不为空时使用左值,否则使用右值。

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

功能等价于:

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

成员属性引用

第一种情况已经在上文中编写你的第一个数据绑定表达式中讨论过:使用简短化的JavaBean引用。当一个表达式引用了一个类的成员属性,他会使用访问变量域相同的格式,getter方法,和ObservableFields(可观察域)。

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

规避空指针异常

自动生成数据绑定代码会检查空变量的存在并设法防止空指针异常。比如,在表达式 @{user.name}中,如果 user 是空, user.name 会被指派默认值(也是null)。如果你引用了

user.age, 而age是int型,那么会被默认赋值为0。

 

集合类型

通常的集合类型有:数组,列表,Sparse(稀疏)列表和map(映射),可以方便地使用 [] 操作符。

 

<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&lt;String>"/>
    <variable name="map"type="Map&lt;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"]}'

It is also possible to use double quotes to surround theattribute value. When doing so, String literals should either use the&quot; or back quote (`).

可能也有一种情况属性值使用双引号包起来,当使用这种做法时,字符串的表示可以使用&quot;作为引号,或者使用后引号( ` )。

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

资源

可以使用正常的语法来访问资源,资源名可以正常的作为表达式的一部分:

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)}"

有一些资源需要明确的类型评估。

Type

Normal Reference

Expression Reference

String[]

@array

@stringArray

int[]

@array

@intArray

TypedArray

@array

@typedArray

Animator

@animator

@animator

StateListAnimator

@animator

@stateListAnimator

color int

@color

@color

ColorStateList

@color

@colorStateList

 

数据对象延伸

任何纯粹的Java对象(POJO)可以用作数据绑定,但是改变一个POJO却不会让UI进行更新。给你的数据对象进行改变时可以进行通知才显出数据绑定真正的威力。有这么三种数据变更通知机制, Observable 可观察对象, ObservableField 可观察域,和observable collections可观察集合。

 

当这些可观察数据对象中的其中一种被绑定到UI上,当一个成员属性变更时,UI将会自动随之更新。

可观察对象

一个实现了android.databinding.Observable 接口的类将允许附加一个单独的监听器到一个绑定对象上以监听数据对象中所有成员属性发生的变更。

一个Observable 接口有一个可以添加和移除监听器的机制,但是通知是开发者决定的。要让开发者更容易使用,因此就有了一个基类BaseObservable, 被用来实现监听的注册机制。数据类的实现者仍然有责任让成员属性变化时进行通知。这是通过指派一个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类中。BR类将会在模块包中生成。如果数据类的基类不能变更, Observable 接口可以使用方便的PropertyChangeRegistry 类实现来有效地存储通知监听器。

 

可观察域

创建可观察类需要做那么一点工作,因此想要省时间的开发者或者有很少的成员属性可以用ObservableField. ObservableFields是自包含有一个单独的变量域持有可观察对象的。这是为了所有的基本类型和引用类型的版本。要使用的话,要在数据类中创建一个公开的不可再赋值的变量域:

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

这就OK了!要访问值,使用set和get访问方法:

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

可观察集合

有一些引用使用动态数据结构去保持数据。可观察集合允许键值访问这些数据对象。ObservableArrayMap在作为键值引用时非常有用,比如使用String。

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

在布局中,映射会通过字符串键名去访问。

<data>
    <import type="android.databinding.ObservableMap"/>
    <variable name="user" type="ObservableMap&lt;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);

在布局中,列表可以使用索引访问具体元素:

<data>
    <import type="android.databinding.ObservableList"/>
    <import type="com.example.my.app.Fields"/>
    <variable name="user" type="ObservableList&lt;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"/>

生成的绑定类

生成的绑定类链接了布局中的布局变量。之前讨论过,名称和包都是可以定制的。生成的绑定类都继承了android.databinding.ViewDataBinding。

创建过程

绑定过程应该在扩展出布局以后紧接着进行以确保View视图层次不会因为布局中整合的绑定View的表达式所干扰。有这么几种方法绑定到一个布局上。最通用的方式是使用在绑定类上使用静态方法。扩展方法扩展出视图层次并且一次性绑定。还有一个更简单的版本,只要使用 LayoutInflater 和 ViewGroup 即可:

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

如果布局已经使用一个不同的机制被扩展出来,他会被分开绑定。

MyLayoutBinding binding =MyLayoutBinding.bind(viewRoot);

有时候绑定不能提前知道,这种情况下,绑定可以通过DataBindingUtil类来创建。

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

有ID的View

会为布局中每一个有ID的View都会生成一个公开的最终变量。绑定过程中,在View层次上会有一个单独的过程,抽出有ID的View。这个机制对于一些View来说会比调用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>

会生成附带有这些内容的绑定类:

public final TextView firstName;
public final TextView lastName;

对于没有数据绑定来说,ID没啥大用,但是仍然有一些实例,从代码中会访问View是很有必要的。

变量

每个变量都将会给与访问方法。

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

会在绑定类中生成setter和getter:

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

ViewStub

ViewStub 会和通常的View不太一样。他们起初是不可见的,并且当他们被置于课件状态或者被明确告知要进行扩展时,他们会在布局中将自己替换成另一个布局。

因为ViewStub在视图层次中基本上就是消失状态,绑定了对象的View也必须消失。因为View是不可以改变的, ViewStubProxy对象会替代ViewStub的位置,当它存在时就可以让开发者能够访问ViewStub,并且当ViewStub被扩展时也可以扩展视图层次。

当扩展另一个布局的时候,一个绑定类必须为新的布局建立起来。这样的话,ViewStubProxy必须监听ViewStub的OnInflateListener,并且同时建立绑定。由于只能存在一个,ViewStubProxy允许开发者设置一个OnInflateListener在建立绑定以后调用。

高级绑定

动态变量

有时候,特定的绑定类不会是已知的类型。比如,一个RecyclerView 适配器Adapter在操作任意布局的时候不知道是哪个特定的绑定类。必须在onBindViewHolder中指派绑定值。

在这个例子中,RecyclerView绑定的所有布局都有一个”item“变量。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();
}

立即绑定

当一个变量或者可观察对象改变时,绑定类会计划在下一帧前变更。然而有时候绑定必须立即执行,要强制执行,就使用 executePendingBindings()方法。

背景线程

只要不是集合,你可以在背景线程中改变你的数据模型。数据绑定会本地化变量/变量域,同时会评估防止任何并发问题。

属性赋值方法setters

无论何时一个绑定的值改变了,生成的绑定类一定会对使用了绑定表达式的 View调用setter方法(译者:说的那么绕,实际就是重新赋值)。数据绑定框架会有一些途径去决定使用哪个方法去设置值。

自动Setter

对于一个attribute,数据绑定会尝试寻找方法setAttribute。对于attribute的命名空间不需要在意,只要关心attribute本身。比如,一个表达式关联的TextView属性 android:text ,会寻找setText(String)。如果表达式返回的是整形,数据绑定会搜寻setText(int)方法。使用表达式要小心的返回正确的类型,必要时强制类型转换。要注意数据绑定即便没有给定的名称的属性存在也会有效。你也可以轻易的”创造”一个属性通过数据绑定给任何setter。例如,支持库DrawerLayout没有任何属性,但是有大量的setter,你可以自动化的使用这些setter方法任何一个。

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

重命名Setter

有一些属性有setter但不能通过命名匹配。对于这些方法,一个属性能够通过BindingMethods注解去手动关联setter。这这必定会关联一个包含BindingMethod注解的类,对应每一个重新命名的方法。例如, android:tint 属性实际上关联的是setImageTintList方法,而不是setTint方法。

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

开发者一般不可能需要重命名setters,Android框架的属性都已经实现了。

自定义Setter

有一些属性需要自定义绑定逻辑。比如,没有任何setter关联 android:paddingLeft属性。

然而却存在 setPadding(left,top, right, bottom) 方法。一个带有BindingAdapter 注解的静态绑定适配的方法可以允许开发者去定制如何为一个属性调用setter。

Android自带属性已经建立了 BindingAdapter。比如就有一个 paddingLeft:

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

绑定适配器对于其他类型的定制很有用。比如,一个定制的加载器能够调用另一个线程加载图像。

当出现冲突时开发者创建的绑定适配器会覆盖数据绑定默认的适配器。

你也可以让适配器接收多个参数:

@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}”/>

如果 imageUrl 和error 都用在ImageView上,imageUrl 是一个字符串并且error是一个绘制对象,这个适配器将会调用。

·        自定义命名空间会在匹配时被忽略

·        你可以为Android命名空间写适配器

转换器

对象数据转换

当一个对象从绑定表达式中返回数据,一个setter将会自动被选择,重命名并定制setter,这个对象就会被强制类型转换到选择的setter方法中中参数的类型。

这是一个方便的使用ObservableMaps保持数据的例子:

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

userMap会返回一个对象,那个对象会被自动强转成setText(CharSequence) setter中发现的参数类型。当可能有模糊不清的参数类型的时候,开发者需要在表达式中使用强制类型转换。

自定义转换

有时候转换应该在特定的类型上自动转换。比如:当设置了背景的时候:

<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){
   retur new ColorDrawable(color);
}

要注意一些转换仅仅发生在setter级别,因此这种混合类型转换是万万不可的:

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

 

 

 

 

 

 

 

 

 

 转载请标明来源地址:http://blog.youkuaiyun.com/lp8800/article/details/46353037

 

 

 

 

Android Jetpack中DataBinding数据绑定-绑定适配器(六) Android Jetpack中DataBinding数据绑定-绑定适配器(六)绑定适配器设置特性值自动选择方法指定自定义方法名称提供自定义逻辑对象转换自动转换对象自定义转换 绑定适配器 绑定适配器负责发出相应的框架调用来设置值。例如,设置属性值就像调用 setText() 方法一样。再比如,设置事件监听器就像调用 setOnClickListener() 方法。 数据绑定库允许您通过使用适配器指定为设置值而调用的方法、提供您自己的绑定逻辑,以及指定返回对象的类型。 设置特性值 只要绑定值发生更改,生成的 阅读详情

相关推荐

RTX 50系显卡实战3DGS:从源码编译到避坑指南

本文详细介绍了在RTX 50系显卡上成功运行3D Gaussian Splatting(3DGS)的完整实战指南。针对新显卡架构与旧版预编译包不兼容的核心问题,文章提供了从源码编译CUDA扩展的清晰步骤,包括环境配置、依赖安装、核心模块diff-gaussian-rasterization和simple-knn的编译避坑方法,并涵盖了数据准备、模型训练与实时预览的全流程,帮助开发者高效利用新硬件进行3D重建。

weixin_28314575的博客 264

Android DataBinding双向绑定相关注解

目录 @InverseMethod @BindingAdapter @InverseBindingAdapter @BindingMethod @InverseBindingMethod @Bindable 在了解DataBinding相关注解前,可以看下这一篇文章“注解介绍”,了解一下什么是注解及注解怎么用。 @InverseMethod 此注解用于方法上,作用为转换数据。用法如下: 新建一个Binding.kt文件,并写如以下代码: @InverseMethod("i...

weixin_43298955的博客 961

虚拟机Ubuntu连接USRP

笔记本通过网线连接USRP。

xiaozir的博客 2309

databinding介绍

1、DataBinding介绍 DataBinding 是 Google 在 Jetpack 中推出的一款数据绑定的支持库,利用该库可以实现在页面组件中直接绑定应用程序的数据源。使其维护起来更加方便,架构更明确简介。所谓的绑定,是绑定什么呢? 数据直接绑定到UI上,数据改变时UI自动更新 UI上的数据绑定到变量中,当数据(如EditText中的数据)改变时自动更新 DataBinding非常适合用于MVVM模式中充当View和ViewModel的双向通讯的工具,引入DataBinding之后,我们可以少

qq_41818873的博客 5551

整车CAN网络错误帧排查方法

本文围绕 CAN 总线错误帧展开,先剖析其产生原因,涵盖物理连接与硬件问题、电磁兼容性问题、总线负载与设计问题及配置问题;再阐述位错误、填充错误等 5 类错误帧类型;接着说明错误帧与总线 BUSOFF 的关系,解析主动 / 被动错误状态及 BUSOFF 的触发与恢复;还结合整车故障案例做实际分析,指出错误帧根源多为线束或控制器问题。最后总结,强调错误帧是 CAN 协议保障高鲁棒性的机制,掌握相关知识助工程师提升 CAN 网络处理能力。

车载网络小D的博客 1248

车辆贷款违约预测挑战赛

2021科大讯飞-车辆贷款违约预测挑战赛--方案简介车贷违约预测问题,目的是建立风险识别模型来预测可能违约的借款人。预测结果为借款人是否可能违约,属于二分类问题。偏数据挖掘的比赛,关键点是如何基于对数据的理解抽象归纳出有用的特征。站在大佬的视角,尝试学习总结,站在巨人的肩膀上,也许看得会更远一些。直接进入主题,开始学习套路,芜湖~特征工程1、常用库、数据导入import pandas as pd import numpy as np import lightgbm as lgb import xgboost

平平淡淡,戒急用忍,一生学闭嘴。 3341

android databinding 的三种自定义属性方式

1、概述 目前发现,databinding 有三种自定义属性的方式。分别是: 1、xml 引入自定义属性标签。代码通过 @BindingAdapter 注解完成绑定 2、直接在代码里使用:@BindingMethods 注解引入自定义属性,再用@BindingAdapter 注解完成绑定 3、自定义控件属性时,提供set的方法 可以自动完成支持 databinding 属性。 属性名字=控件的自...

6896

ZEMAX学习 6.一个照相物镜的设计

曲线越平滑表示场曲越小,曲线越接近水平,系统边缘与中心对比度越接近,虚实越接近表示色差和色散越好;第1个面设计不合理,出现前后表面相交的情况,点击第1面厚度,选择边缘厚度,设置为0.1,第1面厚度被控制在0.1mm厚,系统根据这一设置始终保持第1面边缘厚度为0.1mm。要求:设计一个照相物镜,焦距f=9mm,F#为4,视场角40°;添加有效焦距操作数EFFL 9mm 权重为1,设置优化变量,如下图,ctrl+shift+o打开优化界面。报告中系统数据有效焦距为67.381mm,设计要求为9mm;

qq_24542783的博客 4713

笔记 dataBinding的一些用法

启用dataBinding //在module的build.gradle中 apply plugin: 'kotlin-kapt'//必须 android{ //AS 4.0 以下, dataBinding{ enabled true } //AS 4.1之后 buildFeatures{ dataBinding true // for view binding : // viewBinding true } } UI改造 <layout> &

qq_32798811的博客 419

CANoe UDS $27服务DLL生成实战:从工程配置到算法修改全流程

本文详细介绍了在Vector CANoe中为UDS(统一诊断服务)的$27安全访问服务生成定制化DLL(动态链接库)的全流程。从定位官方参考工程、配置Visual Studio开发环境,到深入解析核心的GenerateKeyEx函数接口,并重点演示了如何修改和实现自定义的种子-密钥安全算法,最终完成DLL的编译、部署与CANoe集成测试,为汽车电子诊断开发提供实战指导。

star5的专栏 535

1.DJI-payload SDK负载开发准备和硬件连接及运行示例代码

大疆psdk开发环境

哒宰的博客 1443

bind绑定方法

类上绑定方法时

Web_Notes的博客 390

博途PLC信号处理系列之卡尔曼滤波程序(Kalman Filter)

三菱系列PLC的卡尔曼滤波程序,可以参看下面这篇博文PLC滤波算法之卡尔曼滤波(kalmanFilter)代码+测试_RXXW_Dor的博客-优快云博客_plc滤波kalman滤波是采用递归的方法解决线性滤波问题,只需要当前的测量值input(西门子PLC里比如我们的模拟量通道AIW0值)和前一个采样周期的估计值(上一个时刻的滤波输出结果last_out)就能进行状态估计,需要的存储空间小,每一步的计算量小。下面我们通过程序代码一一给大家展示下。注意。......

RXXW_Dor的博客 3475

DataBinding 学习系列(4)DataBinding的高级功能

前言前几篇已经DataBinding的基础用法已经介绍的差不多了,所以接下来感受一下DataBinding强大的高级功能。正文DataBinding可以通过注解,实现很多强大的功能,并且十分的方便,能够帮助我们省去大量的对xml进行操作的代码,例如加载图片,字符串处理等等操作。@BindingConversion 自定义类型转换<ImageView android:layout_width

珠穆朗玛小王子的博客 9264

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

android studio字符串转整型,Android Studio 中的FindBugs插件使用,轻松帮你发现Bug (转)...

在日常开发过程中难免会因为一时疏忽而留下一些Bug,这些Bug就是埋在程序里的定时炸弹,如果不能及时铲除就会导致程序的不稳定,异常或闪退的现象,从而导致用户的体验的下降。那么怎么才能找出这些埋在程序里的定时炸弹呢?对程序员来说最头疼的事情莫过于找Bug了,尤其是找自己程序中的Bug,因为人的思维是有误区的,他很容易陷入当时开发程序时的思维,这样就很难发现埋藏在程序中的Bug。接下来就给大家分享一个...

weixin_28996657的博客 702

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

【Jetpack】学穿:DataBinding → 数据绑定 (使用篇)

0x1、引言 ViewBinding(视图绑定) 的作用和原理一言以蔽之: 作用 → 代替findViewById 的同时,还能保证 空安全 和 类型安全,且 支持Java; 原理 → AGP为模块中的每个XML生成绑定类,本质上还是findViewByid,只是自动生成控件实例,并一一对应; 可以把 ViewBinding 看做 DataBinding 功能的 子集,它有的DataBinding都有,而且还多了 数据绑定。 何为数据绑定? 在维基百科中的定义如下: 是将 “提供器” 的数据源与 “消

m0_56255097的博客 1637

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

Android DataBinding 高级用法总结

DataBinding快速上手,布局细节: 1.< data>…< /data>标签内可以有多个 import 标签。你可以在布局文件中像使用 Java 一样导入引用。 2.当类名发生冲突时,可以使用 alias,像这样: < data> <import type=“com.wenzhibin.View” alias=“myView”/> < /data> 3.< data>…< /data>标签内可以有任意数量的 var

yanhuomatou2015的博客 2274

Android DataBinding的使用

一、介绍 本文是用来简记DataBinding使用前的配置及一些情况下的使用。 二、环境配置 在项目的要使用DataBinding的module的gradle构建文件里添加如下文件: android { .... dataBinding { enabled = true } } DataBinding插件将会在你的项目内添加必需提供的以及编译...

zhoufeng的博客 1124

Databinding简单的分析ImageView属性android:src="@{resImgId}"的调用流程

首先看activity_main.xml中的代码: <variable name="resImgId" type="int"/> <variable name="click" type="org.loader.app4.MainActivi

zhuhai__yizhi的专栏 1万+

Android DataBinding完全解析

/**  * 2015年的Google IO大会上,Android 团队发布了一个数据绑定框架(Data Binding Library),官方原生支持 MVVM 模型。  * 以后可以直接在 layout 布局 xml 文件中绑定数据了,无需再 findViewById然后手工设置数据了。其语法和使用方式和 JSP 中的 EL 表达式非常类似。  */ 配置: android

花花young 1万+

Databinding的使用

这段有时间就看了下Databinding,简单记录一下Databinding的使用方式! 一、Databinding简单尝试 首先在Module app下build.gradle中配置databinding android{ ... dataBinding { enabled true } ... } easy!这样就配好了。

brave_shine的博客 1万+

DataBinding使用教程详解

序 针对MVP和MVC架构的理解还是比较清晰的,但是微软早些提出的MVVM还不是很了解,只知道一个词在耳边很热——“数据驱动”。下面通过对MVVM在Android端的实践DataBinding的深入学习来加深对MVVM模式的理解。 DataBinding介绍 DataBinding——数据绑定,是Google对MVVM在Android上的一种实现,可以直接绑定数据到xml中,通过View...

zhangwude2301的专栏 6000

我见过的最好的DataBinding解析

原文在墙外,我只是好文的搬运工。。。棉花糖给 Android 带来的 Data Bindings(数据绑定库)棉花糖给 Android 带来的 Data Bindings(数据绑定库)作者: Yigit Boyar 和 George Mount

afunyusong的专栏 2万+
上一篇: android支持库 Support Libraries v22.1.0
下一篇: 技巧-如何在android项目中将布局文件存放在不同目录中
XellossRyan
博客等级 码龄18年 42粉丝 69原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值