DataBinding使用教程(三):各个注解详解

文章有点长,请做好心理准备

有哪些注解
  • @Bindable
  • @BindingAdapter
  • @BindingBuildInfo
  • @BindingConversion
  • @BindingMethod
  • @BindingMethods
  • @InverseBindingAdapter
  • @InverseBindingMethod
  • @InverseBindingMethods
  • @InverseMethod
  • @Untaggable

以上就是DataBinding中所有的注解,一共11个注解,其中@BindingBuildInfo与@Untaggable这两个注解是hide的,除了这两个之外,其他9个注解在我们日常开发中都有可能用到,但是最常用的只有如下2个注解:
- @Bindable
- @BindingAdapter

本文会讲解所有的注解,而@BindingAdapter注解的使用又相对较难,所以会着重讲解,其他注解也都会有不同深度的讲解。


1. @BindingBuildInfo

作用:在dataBinding生成相关代码时,该注解用来生成相关的databinding信息,信息中包含一个buildId字段。
在源码中也能找到BindingBuildInfo类的身影:

/**
 * 路径:android.databinding.tool.LayoutXmlProcessor
 */
public void writeEmptyInfoClass() {
    Class annotation = BindingBuildInfo.class;
    String classString = "package android.databinding.layouts;\n\nimport " + annotation.getCanonicalName() + ";\n\n@" + annotation.getSimpleName() + "(buildId=\"" + this.mBuildId + "\")\npublic class " + "DataBindingInfo" + " {}\n";
    this.mFileWriter.writeToFile("android.databinding.layouts.DataBindingInfo", classString);
}
2.@Untaggable

作用:在dataBinding中,通过为view设置tag的方式来标记一个view,然后dataBinding生成代码时,会根据这些tag找到对应的view,然后设置相关的属性。@Untaggable注解有一个String数组,用来存储相关的viewType,在生成相关代码时,dataBinding会从该数组中查找viewType,判断该view是否可设置tag。

难道还有DataBinding不支持的操作?那必须的,在fragment标签中就不支持dataBinding相关的开发方式,一用就会抛异常的,自然不能给fragment这种viewType设置tag。

3.@BindingConversion
  • 作用于方法
  • 被该注解标记的方法,被视为dataBinding的转换方法。
  • 方法必须为公共静态(public static)方法,且有且只能有1个参数

问:那到底什么属性要被转换?又要把属性转换成什么呢?
答:举个例子,比如View的android:background=""属性,属性值为drawable类型的对象,如果你要放置一个@color/black的属性值,在不使用dataBinding的情况下没有任何问题,但是如果你要使用了dataBinding方式开发,则会报错,原因在于android:background=""的目标值类型为drawable,而databinding会把@color/black先解析成int类型的颜色值,这时如果把int类型的颜色值直接赋值到目标为drawable类型的参数中去,那绝逼是要报错的,如果我们可以在int类型的颜色值赋值之前,让int类型的颜色值自动转换为colorDrawable对象,就可以解决这个问题,而@BindingConversion注解就是干这个事的。
我们先来看一个官网上的示例:

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

如果只有上面那段代码,那肯定会报错的,原因上面也说了,所以我们需要定义一个转换方法,把整型的颜色值转换为drawable对象:

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

这时再运行就不会出错了,因为在int型颜色值赋值之前已经被自动转换为ColorDrawable了。
肯定有人会有疑问:
- 为什么我没有定义convertColorToDrawable这样的方法,直接写完布局文件就运行也没有报错呢?
- convertColorToDrawable这个方法是什么时机被调用的呢?

首先之所以没有报错的原因,其实是因为convertColorToDrawable这个方法在dataBinding的jar包中已经帮我们定义好了,我们不用再定义了,所以不会报错。源码路径为:android.databinding.adapters.Converters
下面再说说调用时机:Android中的每个xml中的属性其实都对应着相应的java方法的,如果在xml中设置的属性值的类型与对应的Java方法的参数类型不符,这时 dataBinding就会去寻找可以让属性值转换为正确类型的方法,而寻找的根据就是所有被@BindingConversion注解标记的方法,这时convertColorToDrawable方法就会被调用了。

如果我们自己定义了一个功能相同的convertColorToDrawable方法,那么dataBinding会优先使用我们自己定义的方法。
如果我们自己定义了多个功能相同的convertColorToDrawable方法,比如convertColorToDrawable01,convertColorToDrawable02,convertColorToDrawable03,dataBinding会选择顺序靠后的方法去使用,说起来很抽象,举个例子:

public class CustomConversion {
   
    @BindingConversion
    public static ColorDrawable convertColorDrawable01(int color) {
        return new ColorDrawable(color);
    }

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

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

如上代码所示,convertColorToDrawable03方法排在最后面,所以dataBinding会选择convertColorToDrawable03去使用。
但是个人强烈建议不要定义功能重复的方法,你这不是闲的蛋疼吗
但是话说回来,如果我们真的需要定义多个参数类型相同,返回值类型也相同但是方法体中的实现却各不相同的方法,我们希望dataBinding能分辨出方法之间的不同,但是很不幸的是,至少目前来说,dataBinding是看不出这些方法的区别的,所以还是会选择顺序靠后的那个方法,即便我们真正想让它调用的是其他方法,所以这也算是DataBinding的一个不足之处吧。

4.@BindingMethod与@BindingMethods
  • @BindingMethods注解一般用于标记类
  • @BindingMethod注解需要与@BindingMethods注解结合使用才能发挥其功效
  • 用法极其简单,但是使用场景很少(因为大多数场景,dataBinding已经帮我们做好了)

问:@BindingMethod与@BindingMethods存在的意义?
答:为了说明@BindingMethod与@BindingMethods存在的意义,我强行写了一个例子:

...

 <import type="android.view.Gravity"/>

 <TextView
    android:layout_width="match_parent"
    android:layout_height="55dp"
    android:gravity="@{Gravity.CENTER}"/>

...

android:gravity="@{Gravity.CENTER}"属性中我使用了dataBinding表达式设置文本对齐方式,在编译时,dataBinding会根据属性名gravity到TextView源码中寻找对应的setGravity()方法,然后把我们的Gravity.CENTER值设置进去。生成的代码如下:

 this
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值