DataBinding 是一种支持库,借助该库,您可以使用声明性格式(而非程序化地)将布局中的界面组件绑定到应用中的数据源。库是一种支持库,借助该库,您可以使用声明性格式(而非程序化地)将布局中的界面组件绑定到应用中的数据源。
借助布局文件中的绑定组件,您可以移除 Activity 中的许多界面框架调用,使其维护起来更简单、方便。还可以提高应用性能,并且有助于防止内存泄漏以及避免发生 Null 指针异常。
DataBinding 不但灵活而且兼容性广。因此大家可以在Android 4.0(API 级别 14 )的时候进行使用。
如果想要使用 DataBinding,那么大家就需要在Module 的build.gradle 中添加
android {
dataBinding {
enabled = true
}
}
或者
android {
dataBinding.enabled = true
}
如果需要使用DataBinding ,那么大家就需要在xml 布局中符合如下的规则:
在代码中生成绑定类绑定布局的方式有两种:
与普通的xml不同,DataBinding布局文件以根标记 layout 开头,后跟 data 元素和 view 根元素。
标签中盛放数据类型。如:
string 数据类型可以使用如下方式导入
当然
这里使用的View 根标签和我们使用的正常布局一样。
首先我们要知道,系统会为所有使用
生成的绑定类将布局与布局中的视图关联起来。这些类都是从ViewDataBinding 继承而来的。
在上面我们介绍了代码中绑定布局的方式有两种,现在我们就介绍一下。
如图我们可以看见DataBindingUtil 中可以使用 inflate 、bind 、setContentVIew 的方式绑定布局。
其中:
inflate :可以在任意地方进行使用,一般在Fragment / recyclerview 等地方进行使用
bind : 可以在任意地方进行使用。
setContentVIew : 只可以在Activity 中进行使用。
xmlBinding 和上面的DataBindingUtil 相似。
只不过如果使用 xmlBinding 之后必须要使用 setContentView (Activity 中)重新设置数据。
我个人推荐使用 DataBIndingUtil 的方式。大家都知道如果要写项目,那么就会抽取出Base 类,所以我们为了使用的方便一般就自己对于setCOntentView方法进行各种设置。比如我的BaseActviity。
abstract class BaseActviity : AppCompatActivity() {
var mBInding: T? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mBInding = DataBindingUtil.setContentView(this,getLayoutIds())
}
abstract fun getLayoutIds(): Int
}
这样我们就可以在自己的类中使用统一的方式进行设置。
如果有一个 User 类,类中有name 和 age 两个属性,那么我们在布局中设置一个textview 的name 为user的name我们可以在布局中直接使用。
当然,我们这里只是将数据类型添加到了布局中,但是布局仍然不知道内部的数据是上面,所以我们需要对于数据和布局进行绑定。
如,下面的例子:
val mBinding = setContentView(this, R.layout.activity_main)
mBinding.user = User("蔡依林",22)
表达式语言与托管代码中的表达式非常相似。您可以在表达式语言中使用以下运算符和关键字:
如果左边运算数不是 null,则 Null 合并运算符 (??) 选择左边运算数,如果左边运算数为 ,则选择右边运算数
android:text="@{user.displayName ?? user.lastName}"
这在功能上 等效于 三元运算符
android:text="@{user.displayName != null ? user.displayName : user.lastName}"
这个功能就是在上面的时候进行使用的@{}的方式,这里不再次进行介绍。
生成的数据绑定类会自动检查是否有null 值,并且避免空指针异常。例如,在表达式 @{user.name} 中,如果 user 为 Null,则为 user.name 分配默认值 null。如果您引用 user.age,其中 age 的类型为 int,则数据绑定使用默认值 0。
为方便起见,可使用 [] 运算符访问常见集合,例如数组、列表、稀疏列表和映射。
注意:要使 XML 不含语法错误,您必须转义 < 字符。例如:不要写成 List
形式,而是必须写成 List <;String>。
您还可以使用 object.key 表示法在映射中引用值。例如, @{map[key]} 可替换为 @{map.key}。
您可以使用单引号括住特性值,这样就可以在表达式中使用双引号,如以下示例所示
android:text='@{map["firstName"]}'
也可以使用双引号括住特性值。如果这样做,则还应使用反单引号 ` 将字符串字面量括起来:
android:text="@{map[`firstName`]}"
您可以使用以下语法访问表达式中的资源:
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 |
通过数据绑定,您可以编写从视图分派的表达式处理事件(例如,onClick() 方法)。事件特性名称由监听器方法的名称确定,但有一些例外情况。例如,View.OnClickListener 有一个 onClick() 方法,所以该事件的特性为 android:onClick。
有一些专门针对点击事件的事件处理脚本,这些处理脚本需要使用除 android:onClick 以外的特性来避免冲突。您可以使用以下特性来避免这些类型的冲突
类 | Listener setter | 特性 |
---|---|---|
SearchView | setOnSearchClickListener(View.OnClickListener) | android:onSearchClick |
ZoomControls | setOnZoomInClickListener(View.OnClickListener) | android:onZoomIn |
ZoomControls | setOnZoomOutClickListener(View.OnClickListener) | android:onZoomOut |
当然这些事件我们也可以自己进行定义,我们之后再说。
**方法引用:**在表达式中,您可以引用符合监听器方法签名的方法。当表达式求值结果为方法引用时,数据绑定会将方法引用和所有者对象封装到监听器中,并在目标视图上设置该监听器。如果表达式的求值结果为 null,则数据绑定不会创建监听器,而是设置 null 监听器。
**监听器绑定:**这些是在事件发生时进行求值的 lambda 表达式。数据绑定始终会创建一个要在视图上设置的监听器。事件被分派后,监听器会对 lambda 表达式进行求值。
事件可以直接绑定到处理程序方法,类似于android:onClick可以分配给活动中的方法…
使用方式:
1… 定有一个类,类中有一个需要传递view 的方法
open class Click {
fun ztoastClcik(view : View){
}
}
mBinding.click = Click()
方法引用大家可以认为是一个官方原生的监听器,里面只可以传递view,不可以传递其他参数。我个人认为局限性太大。
监听器绑定是在事件发生时运行的绑定表达式。它们类似于方法引用,但允许您运行任意数据绑定表达式。此功能适用于 Gradle 2.0 版及更高版本的 Android Gradle 插件。
使用方式:
open class Click {
fun toastClcik(context:Context, msg: String) {
Toast.makeText(context,msg,Toast.LENGTH_SHORT).show()
}
}
public interface OnClickListener {
void onClick(View var1);
}
当然了,在这里也可以不传递。所传递的参数通过
3.在代码中进行设置
mBinding.msg = "按钮被点击了"
mBinding.contexts = this
mBinding.click = Click()
需要注意的是,如果您监听的事件返回类型不是 void 的值,则您的表达式也必须返回相同类型的值。
监听器表达式功能非常强大,可以使您的代码非常易于阅读。另一方面,包含复杂表达式的监听器会使您的布局难以阅读和维护。这些表达式应该像将可用数据从界面传递到回调方法一样简单。您应该在从监听器表达式调用的回调方法中实现任何业务逻辑。
监听器实现是在绑定数据时创建的,而不是在事件触发时创建的。
通过导入功能,您可以轻松地在布局文件中引用类,就像在托管代码中一样。您可以在 data 元素使用多个 import 元素,也可以不使用。
当类名有冲突时,其中一个类可使用别名重命名。以下示例将 com.example.real.estate 软件包中的 View 类重命名为 Vista:
您可以在 data 元素中使用多个 variable 元素。每个 variable 元素都描述了一个可以在布局上设置、并将在布局文件中的绑定表达式中使用的属性。
变量类型在编译时进行检查,因此,如果变量实现 Observable 或者是可观察集合,则应反映在类型中。如果该变量是不实现 Observable 接口的基类或接口,则变量是“不可观察的”。
如果不同配置(例如横向或纵向)有不同的布局文件,则变量会合并在一起。这些布局文件之间不得存在有冲突的变量定义。
在生成的绑定类中,每个描述的变量都有一个对应的 setter 和 getter。在调用 setter 之前,这些变量一直采用默认的托管代码值,例如引用类型采用 null,int 采用 0,boolean 采用 false,等等。
系统会根据需要生成名为 context 的特殊变量,用于绑定表达式。context 的值是根视图的 getContext() 方法中的 Context 对象。context 变量会被具有该名称的显式变量声明替换。
通过使用应用命名空间和特性中的变量名称,变量可以从包含的布局传递到被包含布局的绑定。
数据绑定不支持 include 作为 merge 元素的直接子元素。