DataBinding
在xml
文件中的使用首先打开dataBinding
开关
使用DataBinding
首先在build.gradle
文件中开启Databinding
同时开启viewBinding
,需要能自动生成xml
的Viewbinding
文件
android {
dataBinding {
enabled = true
}
//或者
buildFeatures {
viewBinding true
dataBinding true
}
}
布局中添加
标签
打开布局文件在布局文件的根布局中alt+回车
,选择Convert to data binding layout
自动生成如下代码
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
data>
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
android.support.constraint.ConstraintLayout>
layout>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data class="ActivityMainBinding">
<variable
name="userBeanDemo1"
type="com.jetpack.demo.UserBean" />
<import
alias="Bean"
type="com.jetpack.demo.UserBean" />
<variable
name="userBeanDemo2"
type="Bean" />
<import type="com.jetpack.demo.UserBean" />
<variable
name="userBeanDemo3"
type="UserBean" />
<variable
name="userListenerDemo4"
type="UserBean.UserListener" />
data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="10dp"
android:orientation="vertical"
tools:context=".MainActivity">
<Button
android:id="@+id/btn_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="按钮1" />
<Button
android:id="@+id/btn_2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="按钮2" />
<EditText
android:id="@+id/et_1"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:hint="输入内容" />
<TextView
android:id="@+id/tv_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
android:textSize="20sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
LinearLayout>
layout>
UserBean
类class UserBean {
var name: String = "user name"
var school: String = "school name"
var age: Int = 10
var sex: String = "男"
var address: String = "地址"
class UserListener {
fun userClick() {
Log.i("tag", "--->>userClick")
}
fun userClick(userBean: UserBean) {
Log.i("tag", "--->>" + userBean.name)
}
}
}
以上为activity_main
文件与UserBean
类两个文件
布局中定义需要的类名
在data
标签中声明xml
中要使用的变量名和导入类的名称
<data>
<variable
name="userBeanDemo1"
type="com.jetpack.demo.UserBean" />
data>
如果Userbean
类被多个variable
的type
属性用到则可以通过import
标签导入
示例代码如下:
<data>
<import
type="com.jetpack.demo.UserBean" />
<variable
name="userBeanDemo2"
type="UserBean" />
<variable
name="userBeanDemo3"
type="UserBean" />
data>
如UseBean
存在相同名称不同路径,则通过alias
定义别名
示例代码如下:
<data>
<import
alias="Bean1"
type="com.jetpack.demo1.UserBean" />
<import
alias="Bean2"
type="com.jetpack.demo2.UserBean" />
<variable
name="demo1"
type="Bean1" />
<variable
name="demo2"
type="Bean2" />
data>
data
标签中的class
属性,用来自定义代码中Activity
中的ViewBinding
使用的
的名称,
如定义成ActivityMainBinding
示例代码如下:
<data class="ActivityMainBinding">
<import type="com.org.UserBean"/>
<import alias="TempUser" type="com.org.other.UserBean" />
<variable
name="bean"
type="UserBean"/>
<variable
name="infoBean"
type="UserBean"/>
<variable
name="userTemp"
type="UserBean"/>
data>
DataBinding
在控件中的使用
xml
中通过default
设置默认名称
设置这个default
的值应该是只在AS
预览布局文件时展示,App
中安装后并不展示这个值,由于userInfo
类中会有默认值
//大括号中进行表达式的展示
android:text="@{infoBean.school}"
//大括号中也可以写代码
android:text="@{String.valueOf(infoBean.school), default=默认名称}"
onCreate()
中通过调用DataBindingUtil.setContentView
代替setContentView()
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
var activityMainBinding = DataBindingUtil.setContentView<ActivityMainBinding>(this,R.layout.activity_main);
//与上行代码等同
//val binding: BindClass = DataBindingUtil.setContentView(this, R.layout.activity_databinding)
var userBean = UserBean();
activityMainBinding.infoBean = userBean
}
调用以下语句以后,界面会自动将UserBean
中的值,赋值显示到页面上,如果不调用页面则显示值为null
此处调用的infobean
对象,是通过xml
中variable
标签的name
属性定义的infobean
activityMainBinding.infoBean = userBean
DataBinding
单向数据绑定build.gradle
中增加包,plugins
中增加kotlin-kapt
和kotlin-parcelize
plugins {
id 'kotlin-kapt'
id 'kotlin-parcelize'
}
UserBean
类中需要进行改造
继承BaseObservable()
针对要绑定的变量进行@Bindable
注解的声明
针对每个绑定变量重写set
方法,通过通过value
给field
赋值
针对var
属性set
与get
方法是默认存在的,所以是对set
进行重写
对持有的当前对象中的属性变化就行通知更新
notifyPropertyChanged(BR.school)
//只通知school
变量
notifyChange()
//全局刷新通知
class UserBean : BaseObservable() {
//school与name两个变量是针对单向数据绑定的实现
@Bindable
var school: String = "school name"
set(value) {
field = value
//只通知有school变量变化的
notifyPropertyChanged(BR.school)
}
@Bindable
var name: String = "user name"
set(value) {
field = value
//全局进行通知
notifyChange()
}
var sex: String = "男"
var age: Int = 10
var address: String = "地址"
}
UserBean
对象中的属性值,就会改变xml文件中的属性userBean.school = "school 2"
上述方式在实现过程中需要重写set
方法,比较麻烦,谷歌官方有另一种单向数据绑定实现方式,对UserBean
类进行改造
如果属性需要传入默认值的话,可以在ObservableField()
方法中传入参数默认值
值的参数类型根据泛型决定
简单方式中不需要继承BaseObservable()
不需要Bindable
注解
属性通过ObservableField
实现
class UserBean : BaseObservable() {
/**
school,age,name为单向数据绑定的简单示例
*/
var school: ObservableField<String> = ObservableField("school name")
var age: ObservableField<Int> = ObservableField(10)
var name: ObservableField<String> = ObservableField("user name")
var sex: String = "男"
var address: String = "地址"
}
通过继承ObservableField
类后需要注意
UserBean
中的属性与方法进行赋值与取值的时候需要通过调用set()
与get()
方法
不能直接userBean.school = "school name"
这样调用
var userBean = UserBean()
//如果UserBean继承BaseObservable类后需要如下调用
userBean.school.set("middle school")
DataBinding
双向数据绑定数据双向绑定
xml
的view
的变化通过@={}
进行绑定,对数据逆向赋值
xml
文件中的内容
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data class="ActivityMainBinding">
<variable
name="userBeanDemo1"
type="com.jetpack.demo.UserBean" />
data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="10dp"
android:orientation="vertical"
tools:context=".MainActivity">
<TextView
android:id="@+id/tv_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{userBeanDemo1.school, default=默认名称}"
android:textSize="20sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<EditText
android:id="@+id/et_1"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:hint="输入学校名称"
android:text="@={userBeanDemo1.school}" />
LinearLayout>
layout>
Activity
的onCreate()
方法中实现
重点是databind.userBeanDemo1 = userBean
语句的调用
var databind: ActivityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main)
var userBean = UserBean()
//通过给userBeanDemo1的赋值,才能进行代码与xml的双向绑定
databind.userBeanDemo1 = userBean
DataBinding
监听事件的绑定UserBean
中实现了监听回调的方法
class UserBean : BaseObservable() {
@Bindable
var school: ObservableField<String> = ObservableField("school name")
@Bindable
var age: ObservableField<Int> = ObservableField(10)
@Bindable
var name: ObservableField<String> = ObservableField("user name")
var sex: String = "男"
var address: String = "地址"
//传入的userBean定义为val
class UserListener(val userBean: UserBean) {
fun userClick(v: View) {
Log.i("tag", "--->>userClick")
userBean.school.set("学校改名")
}
fun userClick(userBean: UserBean) {
Log.i("tag", "--->>" + userBean.name)
}
}
}
xml
文件中实现
<layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools"> <data class="ActivityMainBinding"> <variable name="userBeanDemo" type="com.jetpack.demo.UserBean" /> <variable name="userListenerDemo4" type="com.jetpack.demo.UserBean.UserListener" /> data> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginLeft="10dp" android:orientation="vertical" tools:context=".MainActivity"> <Button android:id="@+id/btn_1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="@{userListenerDemo4.userClick}" android:text="点击修改学校名称" /> <TextView android:id="@+id/tv_1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@{userBeanDemo.school, default=默认名称}" android:textSize="20sp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> LinearLayout>layout>
Activity
中onCreate()
方法内的实现
var databind: ActivityMainBinding = DataBindingUtil.setContentView(this, R.layout.activity_main)var userBean = UserBean()databind.userBeanDemo1 = userBean//初始化userListenervar userListener = UserBean.UserListener(userBean)//给databind的listener赋值databind.userListenerDemo4 = userListener
第一种:
android:onClick="@{()->userListenerDemo4.userClickBean(userBeanDemo1)}"
方法的回调实现
fun userClickBean(userBean: UserBean) { Log.i("tag", "--->>" + userBean.school) userBean.school.set("学校改名") }
第二种:
android:onClick="@{()->userListenerDemo4.userClick()}"
kotlin
代码中回调方法实现
fun userClick() { Log.i("tag", "--->>userClick>>") }
第三种:
android:onClick="@{userListenerDemo4.userClick}"android:onClick="@{userListenerDemo4::userClick}"
kotlin
代码中回调方法实现
fun userClick(v: View) { Log.i("tag", "--->>userClick") }