Jetpack:DataBinding超详细指南-Kotlin版!

本文详述了Jetpack DataBinding在Kotlin中的应用,包括如何设置对象到布局、响应事件、二级页面数据传递,以及自定义BindAdapter。通过实例展示了DataBinding如何简化Android开发,如在XML中直接绑定变量、事件处理和数据响应。同时,介绍了如何实现双向绑定,以及使用ObservableField简化这一过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

android:layout_width=“match_parent”

android:layout_height=“match_parent”>

</androidx.constraintlayout.widget.ConstraintLayout>

在activity中,DataBinding直接生成了对应的setter方法。所以可以直接使用setVideoEntity将对象传递给布局类。如下所示:

val videoEntity = VideoEntity()

//绑定实体类

binding.videoEntity = videoEntity

  • 绑定布局变量

将对象传递进去直接,就可以通过@{}直接在布局文件中将对应的变量绑定给控件了

<TextView

android:text=“@{videoEntity.videoName}” />

<TextView

android:text=“@{videoEntity.videoIntroduction}” />

<TextView

android:text=“@{videoEntity.videoStarring}” />

@{}中也可以直接使用静态方法

<TextView

android:text=“@{String.valueOf(1)}” />

DataBinding响应事件

==================================================================================

通过Button控件,演示DataBinding如何响应onClick事件。

  • 创建布局文件转为DataBinding布局
<?xml version="1.0" encoding="utf-8"?>

<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”>

<androidx.constraintlayout.widget.ConstraintLayout

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”>

</androidx.constraintlayout.widget.ConstraintLayout>

  • 声明一个EventHandleListener专门处理点击事件

class EventHandleListener(private val videoEntity:VideoEntity) {

fun onButtonClick1(view: View) {

Toast.makeText(context, “click1”, Toast.LENGTH_SHORT).show()

}

fun onButtonClick2(view: View) {

Toast.makeText(context, “click2”, Toast.LENGTH_SHORT).show()

}

}

  • 布局中定义EventHandleListener变量,并将点击事件传递进button。通过双冒号语法::进行调用

<variable

name=“eventHandlerLayout”

type=“com.zxf.jetpackrelated.databinding.simpleUse.SimpleDataBindingActivity.EventHandleListener”/>

<Button

android:onClick=“@{eventHandlerLayout::onButtonClick1}”

/>

<Button

android:onClick=“@{eventHandlerLayout::onButtonClick2}”

/>

  • activity中将EventHandleListener传递给布局文件

binding.eventHandler = EventHandleListener(videoEntity)

DataBinding二级页面的绑定

=====================================================================================

简单来说就是怎么将,数据传递到通过<include>标签包裹的二级页面呢?

下面就将上面的按钮响应事件通过<include>包裹一下,将EventHandleListener进行一个二级传递。

  • 在一级页面定义<include>,将上面的按钮布局包裹进来

<include

android:id=“@+id/in_bt”

layout=“@layout/layout_databinding_base” />

  • 在一级页面同样声明一下EventHandleListener变量,可以通过二级页面声明的EventHandleListener的name,将对象直接传递给二级页面

<variable

name=“eventHandler”

type=“com.zxf.jetpackrelated.databinding.simpleUse.SimpleDataBindingActivity.EventHandleListener” />

<include

android:id=“@+id/in_bt”

layout=“@layout/layout_databinding_base”

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”

app:eventHandlerLayout=“@{eventHandler}”/>

BindAdapter简单原理分析

====================================================================================

当启用databinding之后,会生成大量的类,其中包括针对UI的各种命名为XXXBindAdapter的类。

截取一下TextViewBindingAdapter类的部分源码。源码展示了DataBinding库针对android:text属性所编写的代码

@BindingAdapter(“android:text”)

public static void setText(TextView view, CharSequence text) {

final CharSequence oldText = view.getText();

if (text == oldText || (text == null && oldText.length() == 0)) {

return;

}

if (text instanceof Spanned) {

if (text.equals(oldText)) {

return; // No change in the spans, so don’t set anything.

}

} else if (!haveContentsChanged(text, oldText)) {

return; // No content changes, so don’t set anything.

}

view.setText(text);

}

在布局文件中通过@{}绑定的text,最终通过生成的BindingImpl类,调用了对应的setText静态方法。

所以总的来说,在布局文件里面绑定的数据,可以调用到BindingAdapter修饰的静态方法

自定义BindAdapter

=================================================================================

仅官方提供的BindAdapter肯定是不够的,所以需要自定义BindAdapter,实现更多的更复杂的业务关系。

下面展示使用ImageView自定义BindAdapter。

  • BindAdapter注解介绍

@Target(ElementType.METHOD)

public @interface BindingAdapter {

String[] value();

boolean requireAll() default true;

}

  • value 即分配给布局文件中使用的名字

  • requireAll 如果需要一下子定义多个value,用于区别是否所有的都需要,默认为true,如果为true,则布局文件中,一旦使用了其中一个其他的也必须要声明,不然编译不通过。

  • 使用glide进行图片加载

添加依赖和网络访问权限

implementation ‘com.github.bumptech.glide:glide:4.12.0’

annotationProcessor ‘com.github.bumptech.glide:compiler:4.12.0’

  • 定义ImageView的BindAdapter类

需要注意的是,BindingAdapter中的方法均为静态方法。第1个参数为调用者本身,即ImageView;第2个参数是布局文件在调用该方法时传递过来的参数

对于Kotlin来说,只需要将函数声明为顶级函数,就对应java的静态方法了。

@BindingAdapter(“image”)

fun setImage(imageView: ImageView, imageUrl: String?) {

if (imageUrl.isNotNullOrEmpty()) {

Glide.with(imageView)

.load(imageUrl)

.into(imageView)

} else {

imageView.setBackgroundColor(Color.BLUE)

}

}

//isNotNullOrEmpty 是自定义的扩展函数

fun CharSequence?.isNotNullOrEmpty(): Boolean {

return !isNullOrEmpty()

}

  • 布局文件中调用BindingAdapter类

方便期间,直接使用上面的VideoEntity类了,里面有对应的图片地址字段videoImageUrl

然后使用image绑定布局

<ImageView

app:image=“@{videoEntity.videoImageUrl}” />

  • 运行结果(加上之间简单使用的整体结果)

在这里插入图片描述

  • BindAdapter方法重载

如果想网络图片加载url不存在则加载本地资源呢?多传递一个参数就好了,怎么传呢?举个🌰

/**

  • 方法的参数以value={“”,“”}的形式存在

  • 变量requireAll用于告诉DataBinding库这些参数是否都要赋值,默认值为true,即全部需要赋值,这里写成false;

  • 如果设置为true,则对应的属性必须在xml一起生命,否则编译报错

*/

@BindingAdapter(value = [“image”, “defaultImageRes”], requireAll = false)

fun setImage2(imageView: ImageView, imageUrl: String?, @DrawableRes imageRes: Int) {

if (imageUrl.isNotNullOrEmpty()) {

Glide.with(imageView)

.load(imageUrl)

.into(imageView)

} else {

imageView.setImageResource(imageRes)

}

}

  • BindAdapter可选旧值

在某些情况下,可能希望在方法中得到该属性之前的值。假如,在修改控件的padding时,可能希望得到修改前的padding,以防止方法重复调用。

举个🌰

/**、

  • 需要注意的是,使用可选旧值时,方法中的参数顺序需要先写旧值,后写新值。即oldPadding在前,newPadding在后。

*/

@BindingAdapter(value = [“padding”])

fun setPadding(view: View, oldValue: Int, newValue: Int) {

LogUtil.d(“------------paddingValueLog: oldValue: o l d V a l u e n e w V a l u e : oldValue newValue: oldValuenewValue:newValue”)

if (oldValue != newValue) {

view.setPadding(newValue, newValue, newValue, newValue)

}

}

需要注意的是,使用可选旧值时,方法中的参数顺序需要先写旧值,后写新值。即oldPadding在前,newPadding在后。

绑定的代码就不写了,做了个例子,默认设置padding为30,点击时变为60,看一下控制台打印的数据

2021-10-12 11:10:06.690 12768-12768/com.zxf.jetpackrelated D/[setPadding(CustomBindingAdapterKt:74)]: ------------paddingValueLog: oldValue:0 newValue:30

2021-10-12 11:10:08.252 12768-12768/com.zxf.jetpackrelated D/[setPadding(CustomBindingAdapterKt:74)]: ------------paddingValueLog: oldValue:30 newValue:60

很明显看到,程序启动时,padding由0变为30。单击button后,程序由30变为60.

实现双向绑定

=========================================================================

上面所有写的都只是简单的绑定,当数据变化后,目前是没有通知到UI进行刷新,同时UI刷新后,数据也没有变化。

下面通过EditText和TextView控件简单实现双向绑定。

  • 使用BaseObservable实现双向绑定

  • 编写实体类DisplayEntity

class DisplayEntity(

var displayStr: String

)

  • 编写一个用于存放与实现双向绑定相关的业务逻辑的类,继承BaseObservable

class TwoBindingEntityObservable : BaseObservable() {

private val displayEntity: DisplayEntity = DisplayEntity(“双向绑定测试”)

/**

  • 在getter 方法上面增加@Bindable 告诉编译器希望对这个字段进行双向绑定

  • 在xml中直接使用displayStr 进行绑定

*/

@Bindable

fun getDisplayStr(): String = displayEntity.displayStr

/**

  • setter 方法在用户编译edittext的时候被自动调用,需要在这里面对displayStr字段进行手动更新

  • 调用notifyPropertyChanged方法通知观察者数据已变更

  • 需要对值进行判断否则会产生循环调用的问题

*/

fun setDisplayStr(displayStr: String) {

//需要对值进行判断否则会产生循环调用的问题

if (displayStr.isNotNullOrEmpty() && displayStr == displayEntity.displayStr) {

return

}

displayEntity.displayStr = displayStr

notifyPropertyChanged(BR.displayStr)

}

}

初始化时为字段displayStr设置了默认值,接着为该字段写了Getter和Setter方法。注意,在Getter方法前加上了@Bindable标签,告诉编译器,希望对这个字段进行双向绑定。而Setter方法会在用户编辑EditText中的内容时,被自动调用,需要在该方法内对userName字段进行手动更新。

notifyPropertyChanged()是BaseObservable类中的一个方法,会通知UI进行刷新。

  • 设置布局以及activity(注意::双向绑定使用@={})

<variable

name=“entityObservable”

type=“com.zxf.jetpackrelated.databinding.twoWayBinding.TwoBindingEntityObservable” />

<EditText

android:text=“@={entityObservable.displayStr}”/>

<TextView

android:text=“@={entityObservable.displayStr” />

binding.entityObservable = TwoBindingEntityObservable()

  • 这样在编辑EditText的时候,对应的TextView也会展示对应的数据,实现了双向绑定

  • 使用ObservabIeFieId更简单的实现双向绑定

  • 创建ObservabIeFieId

class TwoBindingEntityObservable3 {

val displayEntityField = ObservableField(“双向绑定测试-use observableField”)

}

  • 设置布局和activity

<variable

name=“entityObservable3”

type=“com.zxf.jetpackrelated.databinding.twoWayBinding.TwoBindingEntityObservable3” />

<EditText

android:text=“@={entityObservable3.displayEntityField}”/>

<TextView

android:text=“@={entityObservable3.displayEntityField” />

binding.entityObservable = TwoBindingEntityObservable3()

  • 就可以了,是不是很简单!

databinding默认实现了一系列实现Observable接口的字段类型,可以选择使用

BaseObservable,

ObservableBoolean,

ObservableByte,

ObservableChar,

ObservableDouble,

ObservableField,

ObservableFloat,

ObservableInt,

ObservableLong,

ObservableParcelable,

ObservableShort,

ViewDataBinding

自定义InverseBindingAdapter

===========================================================================================

同理可以自定义BindAdapter实现更加个性化的绑定(通知到UI),那么一样可以自定义当UI变化进行反绑(通知到数据)

这时候就用到了InverseBindingAdapter。

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
img

文末

我总结了一些Android核心知识点,以及一些最新的大厂面试题、知识脑图和视频资料解析。

以后的路也希望我们能一起走下去。(谢谢大家一直以来的支持)

部分资料一览:

  • 330页PDF Android学习核心笔记(内含8大板块)

  • Android学习的系统对应视频

  • Android进阶的系统对应学习资料

  • Android BAT大厂面试题(有解析)

中…(img-jaVCk9tf-1711961106945)]
[外链图片转存中…(img-hsJDpxoH-1711961106945)]
[外链图片转存中…(img-9miAICYJ-1711961106945)]
[外链图片转存中…(img-Tn3ETZGZ-1711961106946)]
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
[外链图片转存中…(img-X8um5aqb-1711961106946)]

文末

我总结了一些Android核心知识点,以及一些最新的大厂面试题、知识脑图和视频资料解析。

以后的路也希望我们能一起走下去。(谢谢大家一直以来的支持)

部分资料一览:

  • 330页PDF Android学习核心笔记(内含8大板块)

[外链图片转存中…(img-HR338Bmw-1711961106946)]

[外链图片转存中…(img-HhbnMWIP-1711961106947)]

  • Android学习的系统对应视频

  • Android进阶的系统对应学习资料

[外链图片转存中…(img-bRYdzjNN-1711961106947)]

  • Android BAT大厂面试题(有解析)

[外链图片转存中…(img-ovHsu6MS-1711961106947)]

本文已被CODING开源项目:《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》收录

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值