(一)概述
DataBinding是Jetpack中实现数据双向绑定的组件。
android {
...
// 开启 dataBinding
dataBinding {
enabled = true
}
}
(二)DataBinding 注解
1)@Bindable
说明:该注解用于双向绑定,需要与 notifyPropertyChanged()方法结合使用
该注解用于标记实体类的方法, 且实体类必须继承BaseObserable.
@Bindable
var hasFavorite: Boolean = false
set(value) {
field = value
notifyPropertyChanged(BR._all)
}
2) @BindingAdapter
/**
* 加载网络图片
*
* 自定义属性:使用@BindingAdapter
* 方法必须为公共静态方法,可以有一到多个参数。
* requireAll = false:可以使用这两个属性中的任一个或同时使用.
* 注意:方法的第一个参数必须是 自定义 XXImageView 本身
*/
@BindingAdapter(value = ["image_url", "isCircle", "radius"], requireAll = false)
fun setImageUrl(view: XXImageView, imgUrl: String, isCircle: Boolean = false, radius: Int = 0) {
val builder = Glide.with(view).load(imgUrl)
if (isCircle) {
builder.transform(CircleCrop())
} else if (radius > 0) {
builder.transform(RoundedCornersTransformation(PixUtils.dp2px(radius), 0))
}
val layoutParams = view.layoutParams
layoutParams?.let {// 设置图片尺寸
if (it.width > 0 && it.height > 0) {
builder.override(it.width, it.height)
}
}
builder.into(view)
}
---例如---
<!-- app:自定义属性=@{data变量名.xxx} -->
<!-- 监听器绑定 android:onClick="@{()->xx.xx(param1, param2…)} -->
<com.mooc.ppjoke.view.PPImageView
android:id="@+id/avatar"
android:layout_width="@dimen/dp_40"
android:layout_height="@dimen/dp_40"
app:image_url="@{user.avatar}"
app:isCircle="@{true}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:onClick="@{()->xx.xx(param1, param2…)}"
tools:src="@mipmap/ic_launcher_round" />
布局内变量引用 layout_xxx.xml:
<data>
<variable
name="feed"
type="com.xxx.xxx.model.Feed" />
<variable
name="tagText"
type="String" />
<!-- 默认会自动导入java.lang.*,除此之外必须手动导入 -->
<import type="android.view.View" />
<import type="android.text.TextUtils" />
</data>
<!-- app:${variable.name} = "@{xxx.xx}" -->
<!-- 例如:app:user 引用的是layout_feed_author布局里定义的user变量 -->
<!--头像昵称区-->
<include
layout="@layout/layout_feed_author"
app:user="@{feed.author}" />
val inflater: LayoutInflater = LayoutInflater.from(context)
val binding = LayoutFeedTypeVideoBinding.inflate(inflater)
说明:通过这个binding 对象就可以拿到所有layout_feed_type_video.xml组件对象和变量。
注意:当导入多个类型时,类型可能会冲突。当类名有冲突时,可以使用别名重命名
<import type="android.view.View"/>
<import type="com.gfd.demo.View” alias="Vista"/>
另外:
1) 只需导入Context:
<import type="android.content.Context" />
就可以使用访问数据绑定的上下文对象context(无需定义变量)
android:onClick="@{()->InteractionPresenter.INSTANCE.openShare(context, feed)}"
2) 可以给 databinding 布局的 xml 变量(如:user)直接赋值:
binding = FragmentMyBinding.inflate(inflater, container, false)
binding.setVariable(BR.user, UserManager.mUser)
资源引用 xxx.xml
<string name="nameFormat">%s---%s</string>
<!--字符串拼接-->
android:text="@{@string/nameFormat(vm.firstName, vm.lastName)}"
android:padding="@{vm.large? @dimen/largePadding : @dimen/smallPadding}"
注意:编写databinding xml布局时,如果编译器不提示详细的错误信息,可以使用命令gradlew compileDebugSource --stacktrace -info或者点击Android Studio右侧Gradle-app->other->assembleDebug来查看具体的错误。
(三)ViewBinding与DataBinding区别
1)ViewBinding
ViewBinding会根据xml布局文件自动生成对应的XXXBinding类,然后通过XXXBinding.inflate(layoutInflater)生成一个对应的binding对象, 这个binding对象包含了这个xml布局文件中具有 ID 的所有视图对象,可以直接引用,省去了findViewById的操作。 binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root)
2)DataBinding
DataBinding是一个数据绑定库,它将xml布局中的界面组件绑定到代码中的数据对象, 可以通过对实体字段添@Bindable注解结合notifyPropertyChanged()实现双向绑定,也可以通过对自定义view添加带@BindingAdapter注解的方法来实现自定义属性。 将xml改成databinding 布局后,这样就可以直接绑定并注入xml了: binding = DataBindingUtil.setContentView(this, R.layout.activity_xxx)
通过导包了解,ViewBinding自动生成的XXXBinding也属于DataBinding,也就是DataBinding包含了ViewBinding。