概述
- 本节是针对只会简单使用DataBinding的开发;
变量
-
在XML中声明的变量分为两种,可观察变量和不可观察变量;可观察变量是指implement了Observable/ObservableList/ObservableMap接口或者是LiveData及子类的对象;其他的则是不可观察变量;可观察变量在变量的某个子属性发生变化时,也会触发自动更新UI,非可观察变量则只有在修改该变量或者调用invalidateAll时,才会触发自动更新UI;
-
Bindable
- Bindable可以应用在Observable实现类的getter方法上,在修改对应属性后,可以通过BR.attrName进行修改通知;
- Bindable注解可以添加多个依赖属性,当任意一个属性发生变更(onPropertyChanged)时,和该Bindable绑定的表达式将重新计算;
-
可观察变量有两种实践方式:一种是在XML中声明多个可观察变量,每个变量都是可观察的;另外一种是在XML中声明极少的实现了Observable的类实例(一个XML最好对应一个可观察变量),变量的属性可以通过Bindable注解达到可观察的目的;
- 个人推荐第二种,结合ViewModel也是一种很好的实践;
- 对于基本类型(int,char,long,String)的数据,数据本身不需要具备可观察特性,通过Bindable注解即可,对于自定义类型,最好是扁平型的,通过实现Observable接口和Bindable注解也可以达到属性可观察;
- 对于多层级的自定义类,如果修改最内层的属性,则无法达到可观察自更新效果;从XML中定义的变量开始,最多能实现两层的可观察自更新属性;
绑定表达式
- 绑定表达式在Databinding中是非常重要的概念,在编译期间,就是通过声明的表达式将View组件绑定到相关数据源,进而生成相关类;
- 绑定表达式是在XML中
@{}
和@={}
中的表达式; - 在<data>中声明的变量可以在绑定表达式中直接使用;
- 绑定表达式支持的运算符和关键字
- 算术运算符
+ - / * %
- 字符串连接运算符
+
- 逻辑运算符
&& ||
- 二元运算符
& | ^
- 一元运算符
+ - ! ~
- 移位运算符
>> >>> <<
- 比较运算符
== > < >= <=
(请注意,< 需要转义为 <) instanceof
- 分组运算符
()
- 字面量运算符 - 字符、字符串、数字、
null
- 类型转换
- 方法调用
- 字段访问
- 数组访问
[]
- 三元运算符
?:
- Null 合并运算符
??
- 属性引用
.
- 集合操作
[]
,可用于数组,列表,映射; - 字面常量
- 资源
@
,但是有些资源类型需要显式指明;
- 算术运算符
- 不能使用的运算
- this
- super
- new
- 显式泛型调用
- 事件处理
- 事件处理分为两种:方法引用和监听器绑定;
- 方法引用:在编译时处理,如果方法不存在或者方法签名与监听器中的方法签名不匹配,则触发编译时错误;在数据绑定时进行创建监听器,如果表达式求值为null,则不创建,否则创建;
- 监听器绑定:在触发事件时,对表达式进行求值;只要返回类型匹配就可以;
- include嵌套
- 当XML中通过include嵌套了另一个XML时,可以通过
bind:
+ 被嵌套XML中声明的变量名将XML中的数据传给被嵌套的XML;
- 当XML中通过include嵌套了另一个XML时,可以通过
- 不建议在XML中写复杂表达式,应尽量移到数据源中;
BindingAdapter
- BindingAdapter注解在方法上,用于将绑定表达式的值设置到对应的View组件上;
- BindingAdapter注解方法格式应该为:
@BindingAdapter(value = {"attr1","attr2",...}, requireAll = true) public static void methodName(View view, Type... old, Type... new);
- 类方法,第一个参数类型为View组件类型,后面的为对应的属性类型,所有的旧值放在前面,新值放在后面,属性个数必须和值个数相等;
- requireAll为true时,只有所有的属性都有绑定表达式时,才会匹配;requireAll为false,只要有一个属性有绑定表达式,也会匹配到该方法;
- 事件处理,只能与一种具有抽象方法的接口或抽象类一起使用;监听器有多个方法时,需要拆分为多个监听器;
BindingConversion
- BindingConversion用于将表达式的值类型转化为BindingAdapter方法接收的值类型;
- BindingConversion是全局的,慎用;
BindingMethods/BindingMethod
- BindingMethod用于将属性和非对应的set方法进行匹配,相当于方法重命名;
BindingAdapter/BindingConversion/BindingMethods/BindingMethod
- 这四类注解用于定义如何将绑定表达式的值绑定到View组件上;通过属性名,View组件类型,绑定表达式值类型来匹配对应的方法进行View更新;
- 在将绑定表达式的值更新到View组件的解决方案中,优先使用BindingMethods/BindingMethod,相当于将View内置的方法重命名;BindingMethods/BindingMethod不能解决时,再使用BindingAdapter,将自定义属性或者自定义逻辑通过BindingAdapter;如果还不能解决,最后使用BindingConversion,通过转化绑定表达式的值类型来匹配对应方法,慎用;
- 一个View组件定义一个相关的ViewBinding类,在类声明上添加BindingMethods/BindingMethod注解,类中声明静态方法,静态方法上添加BindingAdapter注解,另外一个单独的BindingConversion类用来声明类型转化方法,添加BindingConversion注解;
- 对于系统内置的View组件,尽量不要配置对应的绑定属性,使用binding-adapters类库中定义的即可;对于自定义类(非系统内置,非support,androidx中的组件),可以定义一个类来声明该类所有的binding相关的配置;不管是系统内置的View组件还是自定义组件,对于属性名称,最好加一个统一前缀,表明是自定义属性,也方便后期维护;
双向绑定
- 上面的四类注解是单向绑定需要的,双向绑定是基于单向绑定的;
- InverseBindingAdapter
@InverseBindingAdapter("attribute" = attrName, event = attrName + "AttrChange") public static Type getAttr(View view, Type old);
- 注解在方法上,用于从View组件获取当前状态;event表示监听事件,需要另外的BindingAdapter(event)方法对View进行监听绑定;
- InverseBindingMethods/InverseBindingMethod
InverseBindingMethods({InverseBindingMethod( type =android.widget.TextView.class, attribute = "android:text", event = "android:textAttrChanged", method = "getText")})
- 和InverseBindingAdapter类似,不需要定义获取View状态的getter方法,同样需要定义BindingAdapter(event)对View进行监听绑定;
- InverseMethod
InverseMethod("convertIntToString") public static int convertStringToInt(String value);
- 类似于单向绑定中的BindingConversion,逆向转换,但是参数类型,返回类型要和对应的BindingConversion正好相反;
DataBindingComponent
- 以上注解定义的都是针对全局的方法,如果只是某个XML中需要用到特殊的方法进行数据绑定,那么可以通过一个类实现了DataBindingComponent接口(空接口),并且在获取binding对象时,传入该类的对象即可;
- 个人不建议采用这种方式,如果某个XML有特殊的数据绑定逻辑,可以通过在可观察数据源上挂监听更新UI(不用DataBinding自动更新部分);
与AAC结合
- AAC(Android Architecture Component)中很多组件可与DataBinding相结合;
- LiveData
- LiveData可当作可观察数据源;
- ViewModel
- 通过自定义类继承于ViewModel,并实现Observable接口,当作可观察数据源,ViewModel本身又跨配置更改周期;
- Lifecycle
- ViewDataBinding绑定Lifecycle,可实现在非激活状态(onStart之前,onPause之后)不更新UI,激活之后更新UI;
网友评论