DataBinding使用(一):布局和binding表达式
DataBinding使用(二):可观察的数据对象
DataBinding使用(三):DataBinding高级使用
DataBinding通过数据绑定,可以直接在xml中绑定数据并实现一些处理逻辑,实时动态刷新数据。但是由于AndroidStudio对xml语法检查的贫弱,xml布局中的表达式逻辑错误,不能准确定位,debug难度增加。
一、环境配置
在Module级别的build.gradle上添加对DataBinding的支持
android {
....
dataBinding {
enabled = true
}
}
如果在library中使用,那么在该library的Module级别的build.gradle中也需要添加
二、布局和绑定
之前的布局文件是以LinearLayout、RelativeLayout等布局为根布局,DataBinding 的布局文件有些不同:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable name="user" type="com.test.databinding.data.User"/>
</data>
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/tv_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.name}"
android:textSize="30dp"
app:layout_constraintRight_toLeftOf="@+id/tv_age"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<TextView
android:id="@+id/tv_age"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{String.valueOf(user.age)}"
android:textSize="30dp"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toRightOf="@+id/tv_name"
app:layout_constraintTop_toTopOf="parent"/>
</android.support.constraint.ConstraintLayout>
</layout>
通过语法表达式@{ }
和变量user
的属性设置到TextView
中
数据类
data class User( var name:String,var age:Int)
绑定数据
AndroidStudio 会根据layout 文件自动生成一个磨人的Binding类,类命根据layout文件名生成
private lateinit var activityMainBinding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
activityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main)
var user = User("杨过",10)
activityMainBinding.user = user
}
三、表达式
支持的运算符
- 数学运算符:
+ - / * %
- 字符串拼接:
+
- 逻辑运算符:
&& ||
- 二进制:
& | ^
- 一元运算符:
+ - ! ~
- 位运算符:
>> >>> <<<
- 比较:
== > < >= <=
- instanceof
- 组:
()
- 数据类型:
字符, 字符串, 数字, null
- 类型转换
- 方法回调
- 数组:
[ ]
- 三元操作符:
?:
相当于??
不支持的操作 this
super
new
- 泛型
几个常用操作符
- 非空判断
android:text="@{user.name==null?user.name:`小龙女`}"
相当于
android:text="@{user.name??`小龙女`}"
如果user
为空,user.name
默认为null
,如果In
类型user.age
为空,默认为0
- 资源Resources
android:text="@{user.name??@string/app_name}"
- 集合
<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<String>"/>
<variable name="map" type="Map<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]}"
四、variables、Imports、 includes
- Variables
data
元素内可以使用多个variable
元素,每个variable
描述可以在布局上设置属性,用在布局中的表达式绑定
<data>
<variable name="user" type="com.test.databinding.data.User"/>
</data>
- Imports
Imports
可以轻松的引用类型到布局文件中,在data
元素内可以使用零个或多个import
元素
<data>
<import type="android.view.View"/>
</data>
...
<TextView
android:id="@+id/tv_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.name==null?View.VISIBLE : View.GONE}"
android:textSize="30dp"
app:layout_constraintRight_toLeftOf="@+id/tv_age"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
如果类名有冲突时,可以给其中的一个类定义一个别名
<import type="android.view.View"/>
<import type="com.example.real.estate.View" alias="ViewRE"/>
这样就可以使用ViewRE
来引用com.example.real.estate.View
,而view
就可以正常引用android.view.View
<data>
<variable name="user" type="com.test.databinding.data.User"/>
</data>
可以改写成
<data>
<import type="com.test.databinding.data.User"/>
<variable name="user" type="User"/>
</data>
- Includes
用法和以前一样,区别在于可以将变量传递到include
布局的绑定中
<include layout="@layout/user"
app:user="@{user}"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@+id/tv_name"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
/>
user.xml 布局中必须声明user变量
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable name="user" type="com.test.databinding.data.User"/>
</data>
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:context=".MainActivity">
<TextView
android:id="@+id/tv_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.name??@string/app_name}"
android:textSize="30sp"
app:layout_constraintRight_toLeftOf="@+id/tv_age"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<TextView
android:id="@+id/tv_age"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{String.valueOf(user.age)}"
android:textSize="30sp"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toRightOf="@+id/tv_name"
app:layout_constraintTop_toTopOf="parent"/>
</android.support.constraint.ConstraintLayout>
</layout>
五、事件处理
类似于android:onClick
可以指定Activity 中的函数,DataBinding也允许处理从视图中发送的事件,有两种方式:
方法调用和监听绑定,二者的区别在于方法调用在编译时处理,监听绑定在事件发生时处理。
- 方法调用
class Events {
fun showToast(view: View) {
Toast.makeText(view.context, "我被点击了", Toast.LENGTH_SHORT).show()
}
<Button android:layout_width="wrap_content"
android:id="@+id/button"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:text="点击"
android:onClick="@{events::showToast}"
app:layout_constraintTop_toBottomOf="@+id/user_il"
/>
记得在activity
中添加 activityMainBinding.events=Events()
,刚开时用的时候经常忘记,造成方法调用不成功
- 监听绑定
class Info {
fun myInfo(view: View,user: User) {
Toast.makeText(view.context, "我是${user.name},我${user.age}岁", Toast.LENGTH_SHORT).show()
}
}
<Button android:layout_width="wrap_content"
android:id="@+id/button2"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:text="事件监听"
android:onClick="@{()->info.myInfo(view,user)}"
app:layout_constraintTop_toBottomOf="@+id/button1"
/>