Android Architecture Component DataBinding -- Binding adapters(翻译)
Android Architecture Component DataBinding – Binding adapters(翻译)
原文:https://developer.android.com/topic/libraries/data-binding/binding-adapters
Binding adapters 负责对设置值进行适当的框架调用。一个例子是像调用 setText()) 方法去设置属性值。另一个例子是像调用 setOnClickListener()) 方法去设置一个事件监听器。
Data Binding 库允许你去指定设置一个值的方法,提供你自己的绑定逻辑,以及通过使用 adapters 来指定返回对象的类型。
设置属性值
每当绑定的值改变,生成的绑定类必须调用一个 view 的表达式 的 setter 方法。你可以让 Data Binding 自动确定方法,显式声明方法或提供自定义逻辑以选择方法。
自动选择方法
对于名为 name 的属性,库会自动尝试寻找方法 setExample(arg),它接受一个相应的类型作为参数。不考虑属性的命名空间,在搜索方法时只使用属性名称和类型。
举个例子,给定 android:text="@{user.name}" 表达式,库会自动寻找一个 setText(args) 的方法,它接收一个 user.getName() 返回值的类型的参数。如果 user.getName() 返回类型是 String,库会去寻找一个接收一个 String 类型参数的 setText() 方法。如果 user.getName() 返回类型是 int,库会去寻找一个接收一个 int 类型参数的 setText() 方法。表达式必须返回正确的类型,必要时你可以去对返回值进行转型。
甚至没有给定名字的属性存在,Data Binding 也能正常工作。你可以通过 data binding 为任何 setter 创建属性。下面 layout 自动使用 setScrimColor(int)) 和 setDrawerListener(DrawerListener)) 方法作为 app:scrimColor 和 app:drawerListener 属性的 setter 方法。分别为:
1 | <android.support.v4.widget.DrawerLayout |
指定自定义方法名
一些属性的 setter 与名称不匹配。在这种情况下,属性可以使用 BindingMethods 注解进行 setter 的关联。注解可以与类一起使用,并且可以包含多个 BindingMethod 注解,每一个都有一个重命名的方法。BindingMethods 注解可以被加在你 app 中的任何类上面。下面的例子中,android:tint 属性与 setImageTintList(ColorStateList)) 方法关联,而不是 setTint() 方法:
1 |
|
大多数情况下,你不需要重命名 Android Framework 类中的 setters。属性已经使用名称约定实现了自动查找匹配方法。
提供自定义逻辑
一些属性需要自定义绑定逻辑。举个例子,没有一个与 android:paddingLeft 属性关联的 setter。但是提供了 setPadding(left, top, right, bottom)。一个带有 BindingAdapter 注解的,静态的 binding adapter 方法可以允许你自定义属性调用的 setter 是怎么样的。
Android Framework 类的属性已经创建了 BindingAdapter 注解。举例,下面的例子展示了 paddingLeft 属性的 binding adapter:
1 |
|
参数类型是很重要的,第一个参数决定了与属性相关联的 view 的类型。第二个参数决定了给定属性表达式中接收的类型。
Binding adapter 对其它类型的自定义是很有用的。举例,一个工作线程中自定义加载器可以被调用来加载图片。
如果与 Android Framework 冲突,你定义的 binding adapters 会覆盖它。
你的 adapters 也可以接收多个属性,如下:
1 |
|
你可以如下在你的 layout 中使用 adapter。注意,@drawable/venueError 引用了你 app 中的 resource。使用 @{} 包围使它成为一个合法的 binding 表达式。
1 | <ImageView app:imageUrl="@{venue.imageUrl}" app:error="@{@drawable/venueError}" /> |
Data Binding Library 忽略了自定义命名空间以用于匹配。
如果,imageUrl 和 error 都被 ImageView 对象使用,并且 imageUrl 是一个 String,error 是一个 Drawable,adapter 就会被调用。如果你希望它们任何属性被调用时就让 adapter 调用,你可以设置 requireAll) 标志为 false,如下:
1 |
|
当有冲突时,你的 binding adapters 覆盖默认的 data binding adapters。
Binding adapter 方法可以选择在处理器中返回旧值。一个方法声明旧值和新值时应该首先声明 所有 属性的旧值,然后再是新值,如下:
1 |
|
事件处理器只能与只有一个抽象方法的接口或抽象类一起使用,如下:
1 |
|
如下在你的 layout 中使用事件处理器:
1 | <View android:onLayoutChange="@{() -> handler.layoutChanged()}"/> |
当一个监听器有多个方法,必须要把它分割成多个监听器。比如,View.OnAttachStateChangeListener 有两个方法:onViewAttachedToWindow(View)) 和 onViewDetachedFromWindow(View))。对此,库提供了两个接口来区分属性和处理器:
1 | // Translation from provided interfaces in Java: |
因为改变其中一个监听器也会影响另一个,所以你需要一个任意或者全部属性的 adapter。你可以在注解中设置 requireAll) 为 false 来指定不是所有属性都必须设置一个绑定表达式,如下:
1 |
|
上面的例子比一般的稍微复杂一点,因为 View 类使用 addOnAttachStateChangeListener()) 和 removeOnAttachStateChangeListener()) 方法而不是 OnAttachStateChangeListener 的 setter 方法。android.databinding.adapters.ListenerUtil 类帮助保持跟踪之前的监听器,以便于它们在 binding adapter 中便于移除。
通过在接口 OnViewDetachedFromWindow 和 OnViewAttachedToWindow 添加 @TargetApi(VERSION_CODES.HONEYCOMB_MR1) 注解,data binding 代码生成器知道 监听器应该只会在 Android 3.1(API level 12)及以上才会生成,支持的版本与 addOnAttachStateChangeListener()) 方法相同。
对象转化
自动对象转化
当一个 Object 从绑定表达式中返回时,库选择方法来设置属性的值。Object 被转换为所选方法的参数类型。使用 ObservableMap 类来存储数据这个行为在 app 中是很方便的,如下:
1 | <TextView |
你也可以使用 object.key 的方式引用值。比如,上面例子中的 @{userMap[“lastName”]} 可以被替换为 @{userMap.lastName}
表达式中的 userMap 对象返回一个值,它自动转型成 用户通过 android:text 属性设置值的 setText(CharSequence) 方法的参数类型。如果参数类型产生歧义的,你必须要在表达式中进行类型转换。
自定义转换
在一些情况下,在两个特殊的类型之间自定义转换是需要的。比如,View 的 android:background 属性期望是一个 Drawable,但是指定的 color 值是一个 integer。下面的例子展示了属性期望是 Drawable,但是提供的却是 integer:
1 | <View |
每当期望一个 Drawable 并返回一个 integer 时,int 应该要被转换成一个 ColorDrawable。这个转换可以通过使用一个带有 BindingConversion static 的方法做到:
1 |
|
但是,绑定表达式中提供的值类型必须是一致的。不能在同一表达式中使用不同的类型,如下示例所示:
1 | <View |
本文链接:https://blog.wangjiegulu.com/2018/04/15/android_architecture_components_binding_adapters/
版权声明:本博客所有文章除特别声明外,均采用 CC BY 4.0 CN协议 许可协议。转载请注明出处。